Files
novaconium/novaconium/pages/admin/logout/index.php
T
code b882c304b1 Replace Basic Auth with multi-user login, roles, groups, and Lib\Access
Admin login & user management (novaconium/ISSUES.md): session-based
login against a SQLite users table replaces the single-user HTTP Basic
Auth stopgap (admin_username/admin_password_hash and /admin/password-hash
are gone; one admin_auth_enabled flag, off by default with zero DB
footprint). New /admin/login, /admin/logout (POST-only, real page), and
/admin/users pages plus bin/create-admin-user.php.

First user created is the admin; everyone after is registered with a
unique normalized email and an optional group. /admin/* and drafts are
admin-only; Lib\Access gates page content from sidecars
(Access::require('group:members')) with login-redirect/404 responses —
public by default, static pages always public by construction. User
management covers disable/enable, delete, promote/demote, group, email,
and password, with last-active-admin lockout guards.

Also: Session::regenerate() against fixation, friendly missing-PDO-driver
errors in Lib\Db, docs at /admin/docs/access-control and updates across
admin-auth/drafts/sidecars/config/libraries and README/AGENTS.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 00:17:54 +00:00

50 lines
1.7 KiB
PHP

<?php
use App\AdminAuth;
use App\Response;
use Lib\Csrf;
use Lib\Input;
use Lib\Session;
// Same two-step config load as /admin/login — see that sidecar. 404 when
// admin auth is off so this route has zero footprint (no session cookie,
// no Lib\Db touch) on a site that never opted in.
$config = require __DIR__ . '/../../../config.php';
$appConfigFile = __DIR__ . '/../../../../App/config.php';
if (is_file($appConfigFile)) {
$config = array_merge($config, require $appConfigFile);
}
if (!$config['admin_auth_enabled']) {
return Response::html('404 Not Found', 404);
}
// A real page now, replacing the hardcoded pre-router special case
// bootstrap.php needed back when logout meant tricking the browser into
// dropping cached Basic Auth credentials. Unlike then, this is a real
// server-side logout: the session's user id is gone afterwards, whatever
// the browser resends.
//
// POST-only, with a GET confirm form, same shape as /admin/clear-cache —
// NOT a logout-on-GET link. Sidecars must be side-effect-free on GET
// (ordinary HTTP hygiene, and the content-index crawl relies on it: it
// invokes every page's sidecar the way a real GET would, so a
// logout-on-GET here would silently end the crawling admin's own session
// the first time a lazy reindex rendered this page).
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!Csrf::verify(Input::post('csrf_token'))) {
return Response::redirect('/admin/logout?error=security', 303);
}
AdminAuth::logout();
Session::flash('admin_notice', 'You have been logged out.');
return Response::redirect('/admin/login', 303);
}
return [
'securityError' => Input::get('error') === 'security',
'csrfField' => Csrf::fieldName(),
'csrfToken' => Csrf::token(),
];