adding active code
This commit is contained in:
parent
675156eee1
commit
b608d55567
13
db/migrations/20260218_create_license_table.sql
Normal file
13
db/migrations/20260218_create_license_table.sql
Normal 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
118
index.php
@ -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);
|
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 '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 'db/BackupService.php';
|
||||||
require_once 'includes/accounting_helper.php';
|
require_once 'includes/accounting_helper.php';
|
||||||
|
|
||||||
@ -571,6 +643,7 @@ $page_permissions = [
|
|||||||
'role_groups' => 'users_view',
|
'role_groups' => 'users_view',
|
||||||
'users' => 'users_view',
|
'users' => 'users_view',
|
||||||
'backups' => 'users_view',
|
'backups' => 'users_view',
|
||||||
|
'logs' => 'users_view',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (isset($page_permissions[$page]) && !can($page_permissions[$page])) {
|
if (isset($page_permissions[$page]) && !can($page_permissions[$page])) {
|
||||||
@ -1397,6 +1470,17 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?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>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -5576,6 +5660,40 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</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; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
130
lib/LicenseService.php
Normal file
130
lib/LicenseService.php
Normal 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.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
53
licensing_server_sample.php
Normal file
53
licensing_server_sample.php
Normal 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]);
|
||||||
|
}
|
||||||
@ -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: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:10:56 - POST: {"id":"7","delete_role_group":""}
|
||||||
2026-02-18 10:12:05 - POST: {"create_backup":""}
|
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":""}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user