adding active code

This commit is contained in:
Flatlogic Bot 2026-02-18 10:48:24 +00:00
parent 675156eee1
commit b608d55567
5 changed files with 317 additions and 0 deletions

View File

@ -0,0 +1,13 @@
-- Migration: Create system_license table
-- Created at: 2026-02-18
CREATE TABLE IF NOT EXISTS system_license (
id INT AUTO_INCREMENT PRIMARY KEY,
license_key VARCHAR(255) NOT NULL,
activation_token TEXT DEFAULT NULL,
fingerprint VARCHAR(255) DEFAULT NULL,
status ENUM('pending', 'active', 'expired', 'suspended') DEFAULT 'pending',
activated_at DATETIME DEFAULT NULL,
last_checked_at DATETIME DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

118
index.php
View File

@ -23,6 +23,78 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
file_put_contents('post_debug.log', date('Y-m-d H:i:s') . " - POST: " . json_encode($_POST) . "\n", FILE_APPEND);
}
require_once 'db/config.php';
require_once 'lib/LicenseService.php';
// Licensing Middleware
$is_activated = LicenseService::isActivated();
$page = $_GET['page'] ?? 'dashboard';
if (!$is_activated && $page !== 'activate') {
header("Location: index.php?page=activate");
exit;
}
// Activation Page UI (accessible without login)
if ($page === 'activate') {
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['activate'])) {
$res = LicenseService::activate($_POST['license_key'] ?? '');
if ($res['success']) {
$success = "System activated successfully! Redirecting...";
header("refresh:2;url=index.php");
} else {
$error = $res['error'];
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Product Activation</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { background: #f4f7f6; height: 100vh; display: flex; align-items: center; justify-content: center; font-family: 'Inter', sans-serif; }
.activation-card { background: white; padding: 2rem; border-radius: 1rem; box-shadow: 0 10px 25px rgba(0,0,0,0.05); width: 100%; max-width: 450px; }
.fingerprint { background: #eee; padding: 0.5rem; border-radius: 0.5rem; font-family: monospace; font-size: 0.8rem; word-break: break-all; }
</style>
</head>
<body>
<div class="activation-card">
<h3 class="fw-bold mb-3">Activate Product</h3>
<p class="text-muted small mb-4">Please enter your serial key to continue using the application.</p>
<?php if ($error): ?>
<div class="alert alert-danger small"><?= $error ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success small"><?= $success ?></div>
<?php endif; ?>
<form method="POST">
<div class="mb-3">
<label class="form-label small fw-bold">Serial Key</label>
<input type="text" name="license_key" class="form-control" placeholder="FLAT-XXXX-XXXX-XXXX" required>
<div class="form-text mt-1" style="font-size: 0.7rem;">Example: FLAT-8822-1192-3301</div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold text-muted">Server Fingerprint</label>
<div class="fingerprint text-muted"><?= LicenseService::getFingerprint() ?></div>
</div>
<button type="submit" name="activate" class="btn btn-primary w-100 py-2">Activate Now</button>
</form>
<div class="mt-4 text-center">
<p class="text-muted small">Need a key? <a href="#">Contact Support</a></p>
</div>
</div>
</body>
</html>
<?php
exit;
}
require_once 'db/BackupService.php';
require_once 'includes/accounting_helper.php';
@ -571,6 +643,7 @@ $page_permissions = [
'role_groups' => 'users_view',
'users' => 'users_view',
'backups' => 'users_view',
'logs' => 'users_view',
];
if (isset($page_permissions[$page]) && !can($page_permissions[$page])) {
@ -1397,6 +1470,17 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</a>
</div>
<?php endif; ?>
<!-- Version & Logs -->
<div class="mt-5 px-4 pb-4 border-top pt-4 sidebar-footer">
<div class="d-flex align-items-center justify-content-between text-muted small mb-2">
<span><i class="bi bi-info-circle me-1"></i> v1.2.5</span>
<span class="badge bg-success-subtle text-success border border-success-subtle rounded-pill">Stable</span>
</div>
<a href="?page=logs" class="text-decoration-none text-muted small d-block">
<i class="bi bi-journal-text me-1"></i> <span data-en="System Logs" data-ar="سجلات النظام">System Logs</span>
</a>
</div>
</nav>
</div>
@ -5576,6 +5660,40 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</table>
</div>
</div>
<?php elseif ($page === 'logs'): ?>
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center border-0">
<div>
<h5 class="m-0 fw-bold text-primary" data-en="System Logs" data-ar="سجلات النظام">System Logs</h5>
<p class="text-muted small mb-0" data-en="Monitor system activity and errors" data-ar="مراقبة نشاط النظام والأخطاء">Monitor system activity and errors</p>
</div>
<div class="d-flex gap-2">
<button onclick="window.location.reload()" class="btn btn-outline-primary btn-sm rounded-pill">
<i class="bi bi-arrow-clockwise"></i> Refresh
</button>
</div>
</div>
<div class="card-body p-0">
<div class="bg-dark text-light p-4 font-monospace small" style="max-height: 600px; overflow-y: auto;">
<?php
$log_files = ['error_log', 'login_debug.log', 'post_debug.log'];
$found_logs = false;
foreach ($log_files as $file) {
$path = __DIR__ . '/' . $file;
if (file_exists($path) && is_readable($path)) {
$found_logs = true;
echo "<div class='mb-4'><h6 class='text-warning border-bottom border-secondary pb-2'>--- " . htmlspecialchars(basename($file)) . " ---</h6>";
$lines = shell_exec("tail -n 50 " . escapeshellarg($path));
echo "<pre class='mb-0 text-info'>" . htmlspecialchars((string)$lines) . "</pre></div>";
}
}
if (!$found_logs) {
echo "<div class='text-center py-5'><i class='bi bi-journal-x fs-1 opacity-25'></i><p class='mt-2 opacity-50'>No accessible log files found.</p></div>";
}
?>
</div>
</div>
</div>
<?php endif; ?>
</div>

130
lib/LicenseService.php Normal file
View File

@ -0,0 +1,130 @@
<?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) {
// In a real production environment, this would hit your licensing server.
// For this demonstration, we simulate the request logic.
$url = self::$remote_api_url . $endpoint;
/*
// Real implementation would look like this:
$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']);
$resp = curl_exec($ch);
curl_close($ch);
$data = json_decode($resp, true);
return $data;
*/
// SIMULATION: If the key starts with 'FLAT-' (case-insensitive), we treat it as valid.
$clean_key = strtoupper(trim($params['license_key'] ?? ''));
if (strpos($clean_key, 'FLAT-') === 0) {
// Check if it's a verification request
if ($endpoint === '/verify') {
return ['success' => true];
}
return [
'success' => true,
'activation_token' => hash('sha256', $params['license_key'] . $params['fingerprint'] . 'SECRET_SALT')
];
}
return [
'success' => false,
'error' => 'License key invalid or expired. Please contact support.'
];
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* SAMPLE LICENSE MANAGER SERVER
* This would be hosted on your own server (e.g., https://licensing.your-domain.com/api/v1)
*/
header('Content-Type: application/json');
// 1. Mock Database of valid keys
$valid_keys = [
'FLAT-8822-1192-3301' => ['status' => 'active', 'max_activations' => 1],
'FLAT-TEST-KEY-0001' => ['status' => 'active', 'max_activations' => 3],
];
// 2. Mock Database of current activations (Key => Fingerprint)
$activations = [
// 'FLAT-8822-1192-3301' => 'hash_from_client'
];
$input = json_decode(file_get_contents('php://input'), true);
$endpoint = $_SERVER['PATH_INFO'] ?? '';
if ($endpoint === '/activate') {
$key = strtoupper(trim($input['license_key'] ?? ''));
$fingerprint = $input['fingerprint'] ?? '';
if (!isset($valid_keys[$key])) {
echo json_encode(['success' => false, 'error' => 'Invalid license key.']);
exit;
}
if ($valid_keys[$key]['status'] !== 'active') {
echo json_encode(['success' => false, 'error' => 'License is expired or suspended.']);
exit;
}
// Check if already activated on another machine
if (isset($activations[$key]) && $activations[$key] !== $fingerprint) {
echo json_encode(['success' => false, 'error' => 'License already in use on another server.']);
exit;
}
// Success: Return a signed token
echo json_encode([
'success' => true,
'activation_token' => hash_hmac('sha256', $key . $fingerprint, 'YOUR_SECRET_SERVER_SALT')
]);
}
if ($endpoint === '/verify') {
// Similar logic to check if the token is still valid or if the key was revoked
echo json_encode(['success' => true]);
}

View File

@ -6,3 +6,6 @@
2026-02-18 10:10:35 - POST: {"name":"Accountant","permissions":["accounting_view","accounting_add","accounting_edit"],"add_role_group":""}
2026-02-18 10:10:56 - POST: {"id":"7","delete_role_group":""}
2026-02-18 10:12:05 - POST: {"create_backup":""}
2026-02-18 10:46:04 - POST: {"license_key":"Flat-8822-1192-3301","activate":""}
2026-02-18 10:46:14 - POST: {"license_key":": FLAT-8822-1192-3301","activate":""}
2026-02-18 10:48:04 - POST: {"license_key":" FLAT-8822-1192-3301","activate":""}