Add system update feature, git-ignore local configs, and fix homepage request logging
- Exclude config.json and admin.json in .gitignore so live settings/passwords are never overwritten by git - Auto-generate config.json and admin.json with defaults if missing - Add config.json.example and admin.json.example reference templates - Add System Update page (/admin/update) in Admin Console to pull updates via Git with 1 click - Log effective page name in index.php instead of literal 'auto' - Add extra HAProxy/PFSense proxy headers to RequestLogger::getClientIp()
This commit is contained in:
@@ -21,6 +21,10 @@ Thumbs.db
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
# Local configuration & credentials
|
||||
config.json
|
||||
admin/config/admin.json
|
||||
|
||||
# No content
|
||||
content/
|
||||
!content/.gitkeep
|
||||
|
||||
+27
-2
@@ -20,10 +20,35 @@ class AdminAuth
|
||||
private function loadAdminConfig(): array
|
||||
{
|
||||
$path = $this->config['admin_config'];
|
||||
$examplePath = dirname($path) . '/admin.json.example';
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return ['users' => [], 'security' => []];
|
||||
if (file_exists($examplePath)) {
|
||||
@copy($examplePath, $path);
|
||||
} else {
|
||||
$defaultAdminConfig = [
|
||||
'users' => [
|
||||
[
|
||||
'username' => 'admin',
|
||||
'password_hash' => password_hash('admin', PASSWORD_BCRYPT),
|
||||
'role' => 'admin',
|
||||
'created' => date('Y-m-d'),
|
||||
]
|
||||
],
|
||||
'security' => [
|
||||
'session_timeout' => 1800,
|
||||
'max_login_attempts' => 5,
|
||||
'lockout_duration' => 900,
|
||||
]
|
||||
];
|
||||
$dir = dirname($path);
|
||||
if (!is_dir($dir)) {
|
||||
@mkdir($dir, 0755, true);
|
||||
}
|
||||
$data = json_decode(file_get_contents($path), true);
|
||||
@file_put_contents($path, json_encode($defaultAdminConfig, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
}
|
||||
$data = file_exists($path) ? json_decode(file_get_contents($path), true) : null;
|
||||
return is_array($data) ? $data : ['users' => [], 'security' => []];
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,11 @@ $layoutSidebarColor = $layoutThemeConfig['header_color'] ?? '#0a369d';
|
||||
<i class="bi bi-journal-text"></i> Logs
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= ($route ?? '') === 'update' ? 'active' : '' ?>" href="/admin/update">
|
||||
<i class="bi bi-cloud-arrow-down"></i> Update
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item mt-3">
|
||||
<a class="nav-link" href="/" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right"></i> Website bekijken
|
||||
@@ -168,6 +173,9 @@ $layoutSidebarColor = $layoutThemeConfig['header_color'] ?? '#0a369d';
|
||||
case 'logs':
|
||||
require __DIR__ . '/pages/logs.php';
|
||||
break;
|
||||
case 'update':
|
||||
require __DIR__ . '/pages/update.php';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</main>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<h2 class="mb-4"><i class="bi bi-cloud-arrow-down"></i> Systeem Update</h2>
|
||||
|
||||
<?php if (!empty($updateOutput)): ?>
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<i class="bi bi-terminal"></i> Update Resultaten
|
||||
</div>
|
||||
<div class="card-body bg-dark text-light p-3">
|
||||
<pre class="m-0 text-light" style="font-family: monospace; font-size: 0.9rem;"><?= htmlspecialchars($updateOutput) ?></pre>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-info-circle"></i> Systeeminformatie
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<strong>Huidige CMS Versie:</strong>
|
||||
<span class="badge bg-primary ms-2"><?= htmlspecialchars($cmsVersion ?? '1.7.1') ?></span>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<strong>Configuratiestatus:</strong>
|
||||
<span class="badge bg-success ms-2"><i class="bi bi-check-circle"></i> Lokaal afgeschermd (Git-safe)</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted small mb-0">
|
||||
Lokale configuratiebestanden (zoals <code>config.json</code> en <code>admin.json</code>) zijn uitgesloten van Git.
|
||||
Hierdoor blijven je instellingen, wachtwoorden en content veilig behouden tijdens het bijwerken.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-arrow-repeat"></i> CodePress CMS Bijwerken
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Haal automatisch de nieuwste CMS updates op via het Git repository.</p>
|
||||
|
||||
<?php if (!empty($gitBranch)): ?>
|
||||
<div class="mb-3">
|
||||
<small class="text-muted">Git branch: <code><?= htmlspecialchars($gitBranch) ?></code></small>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="/admin/update">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
<button type="submit" class="btn btn-primary btn-lg" onclick="return confirm('Weet je zeker dat je het systeem wilt bijwerken naar de nieuwste versie?')">
|
||||
<i class="bi bi-cloud-download"></i> Systeem nu bijwerken
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -29,6 +29,8 @@ class RequestLogger
|
||||
'HTTP_CF_CONNECTING_IP',
|
||||
'HTTP_X_REAL_IP',
|
||||
'HTTP_CLIENT_IP',
|
||||
'HTTP_X_CLIENT_IP',
|
||||
'HTTP_X_CLUSTER_CLIENT_IP',
|
||||
'HTTP_X_FORWARDED_FOR',
|
||||
'HTTP_X_FORWARDED',
|
||||
'HTTP_FORWARDED_FOR',
|
||||
|
||||
@@ -2,6 +2,42 @@
|
||||
|
||||
// Simple configuration loader
|
||||
$configJsonPath = __DIR__ . '/../../config.json';
|
||||
$configExamplePath = __DIR__ . '/../../config.json.example';
|
||||
|
||||
// Auto-create config.json if it does not exist
|
||||
if (!file_exists($configJsonPath)) {
|
||||
if (file_exists($configExamplePath)) {
|
||||
@copy($configExamplePath, $configJsonPath);
|
||||
} else {
|
||||
$defaultConfig = [
|
||||
'site_title' => 'CodePress',
|
||||
'content_dir' => 'content',
|
||||
'templates_dir' => 'cms/templates',
|
||||
'active_theme' => 'default',
|
||||
'default_page' => 'auto',
|
||||
'language' => [
|
||||
'default' => 'nl',
|
||||
'available' => ['nl', 'en']
|
||||
],
|
||||
'seo' => [
|
||||
'description' => 'CodePress CMS - Lightweight file-based content management system',
|
||||
'keywords' => 'cms, php, content management, file-based'
|
||||
],
|
||||
'author' => [
|
||||
'name' => 'E. Noorlander',
|
||||
'website' => 'https://noorlander.info'
|
||||
],
|
||||
'show_version' => true,
|
||||
'enabled_plugins' => ['MQTTTracker', 'HTMLBlock'],
|
||||
'features' => [
|
||||
'auto_link_pages' => true,
|
||||
'search_enabled' => true,
|
||||
'breadcrumbs_enabled' => true
|
||||
]
|
||||
];
|
||||
@file_put_contents($configJsonPath, json_encode($defaultConfig, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists($configJsonPath)) {
|
||||
$jsonContent = file_get_contents($configJsonPath);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"site_title": "CodePress",
|
||||
"content_dir": "content",
|
||||
"templates_dir": "cms\/templates",
|
||||
"templates_dir": "cms/templates",
|
||||
"active_theme": "default",
|
||||
"default_page": "newest",
|
||||
"default_page": "auto",
|
||||
"language": {
|
||||
"default": "nl",
|
||||
"available": [
|
||||
@@ -17,13 +17,12 @@
|
||||
},
|
||||
"author": {
|
||||
"name": "E. Noorlander",
|
||||
"website": "https:\/\/noorlander.info"
|
||||
"website": "https://noorlander.info"
|
||||
},
|
||||
"show_version": true,
|
||||
"enabled_plugins": [
|
||||
"MQTTTracker",
|
||||
"HTMLBlock",
|
||||
"test"
|
||||
"HTMLBlock"
|
||||
],
|
||||
"features": {
|
||||
"auto_link_pages": true,
|
||||
@@ -87,7 +87,8 @@ CodePress CMS is een lichtgewicht, file-based content management systeem gebouwd
|
||||
- **Media beheer** - Uploaden en verwijderen van mediabestanden in `content/-assets/`
|
||||
- **Gebruikersbeheer** - Gebruikers toevoegen, verwijderen, wachtwoorden wijzigen
|
||||
- **Handleiding** - Ingebouwde documentatie met API referentie
|
||||
- **Logging** - Activiteiten log en requests log met IP, pagina, domein; te bekijken en downloaden via `/admin/logs`
|
||||
- **Systeem Update** - Eenvoudig de site bijwerken via `/admin/update` met één klik via Git pull
|
||||
- **Git-safe Configuratie** - `config.json` en `admin/config/admin.json` worden automatisch gegenereerd als ze niet bestaan en zijn uitgesloten van Git, waardoor wachtwoorden en instellingen behouden blijven bij updates
|
||||
- **Bot & AI blokkering** - Automatische 403 voor bekende bots en AI-crawlers
|
||||
- Session-based authenticatie met bcrypt hashing
|
||||
- CSRF-bescherming, brute-force lockout (5 pogingen, 15 min)
|
||||
@@ -315,6 +316,7 @@ Media bestanden (afbeeldingen, PDFs, video, audio) kunnen in elke `content/` sub
|
||||
| `users` | Gebruikersbeheer |
|
||||
| `guide` | Handleiding (deze documentatie) |
|
||||
| `logs` | Log viewer (activiteiten + requests) |
|
||||
| `update` | Systeem update via Git pull (één-klik update) |
|
||||
|
||||
### Editor Functionaliteit
|
||||
|
||||
|
||||
@@ -88,6 +88,10 @@ switch ($route) {
|
||||
handleConfig($auth, $appConfig);
|
||||
break;
|
||||
|
||||
case 'update':
|
||||
handleUpdate($auth, $appConfig);
|
||||
break;
|
||||
|
||||
case 'theme':
|
||||
handleTheme($auth, $appConfig);
|
||||
break;
|
||||
@@ -1518,6 +1522,65 @@ function handleLogs(AdminAuth $auth, array $config): void
|
||||
require __DIR__ . '/../admin/templates/layout.php';
|
||||
}
|
||||
|
||||
function handleUpdate(AdminAuth $auth, array $config): void
|
||||
{
|
||||
$user = $auth->getCurrentUser();
|
||||
$csrf = $auth->getCsrfToken();
|
||||
$message = '';
|
||||
$messageType = '';
|
||||
$updateOutput = '';
|
||||
|
||||
// Load CMS version
|
||||
$versionFile = $config['codepress_root'] . '/version.php';
|
||||
$cmsVersion = '1.7.1';
|
||||
if (file_exists($versionFile)) {
|
||||
$verData = require $versionFile;
|
||||
$cmsVersion = is_array($verData) ? ($verData['version'] ?? '1.7.1') : '1.7.1';
|
||||
}
|
||||
|
||||
// Get git branch
|
||||
$gitBranch = 'main';
|
||||
if (function_exists('exec')) {
|
||||
@exec('git rev-parse --abbrev-ref HEAD 2>&1', $branchOutput);
|
||||
if (!empty($branchOutput[0]) && strpos($branchOutput[0], 'fatal') === false) {
|
||||
$gitBranch = trim($branchOutput[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!$auth->verifyCsrf($_POST['csrf_token'] ?? '')) {
|
||||
$message = 'Ongeldige CSRF token.';
|
||||
$messageType = 'danger';
|
||||
} else {
|
||||
$root = $config['codepress_root'];
|
||||
$cmd = 'cd ' . escapeshellarg($root) . ' && git pull origin ' . escapeshellarg($gitBranch) . ' 2>&1';
|
||||
|
||||
$outputLines = [];
|
||||
$returnCode = -1;
|
||||
if (function_exists('exec')) {
|
||||
@exec($cmd, $outputLines, $returnCode);
|
||||
$updateOutput = implode("\n", $outputLines);
|
||||
} else {
|
||||
$updateOutput = 'exec() is uitgeschakeld op de PHP server.';
|
||||
$returnCode = 1;
|
||||
}
|
||||
|
||||
if ($returnCode === 0) {
|
||||
adminLog($config, 'info', $user['username'] . ' voerde een succesvolle systeemupdate uit');
|
||||
$message = 'Systeem succesvol bijgewerkt naar de nieuwste versie!';
|
||||
$messageType = 'success';
|
||||
} else {
|
||||
adminLog($config, 'warning', $user['username'] . ' probeerde een systeemupdate uit te voeren: ' . $updateOutput);
|
||||
$message = 'Fout bij het bijwerken van het systeem. Bekijk de resultaten hieronder.';
|
||||
$messageType = 'danger';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$route = 'update';
|
||||
require __DIR__ . '/../admin/templates/layout.php';
|
||||
}
|
||||
|
||||
// --- Frontmatter helpers ---
|
||||
|
||||
function parseFrontmatterField(string $content, string $key, string $default = ''): string
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ if (!str_starts_with($path, '/-media/') && !str_starts_with($path, '/-assets/'))
|
||||
$requestLogFile = dirname(__DIR__) . '/admin/storage/logs/requests.log';
|
||||
$logger = new RequestLogger($requestLogFile);
|
||||
$logger->log(
|
||||
$_GET['page'] ?? $config['default_page'] ?? 'index',
|
||||
$_GET['page'] ?? $cms->getEffectiveDefaultPage(),
|
||||
RequestLogger::getClientIp(),
|
||||
$_SERVER['HTTP_USER_AGENT'] ?? '',
|
||||
$_SERVER['HTTP_REFERER'] ?? '',
|
||||
|
||||
Reference in New Issue
Block a user