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);
|
||||
}
|
||||
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
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: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":""}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user