Files
novaconium/App/config.php
T
code 4862526fa1 Add draft pages (admin-only preview); fix admin panel cache leak
Lets a page under App/pages/ be previewed by an admin before the public
can see it: list its route in draft_routes (App/config.php), checked in
bootstrap.php alongside the existing /admin/* gate. Not authenticated ->
same plain 404 an unmatched route gets, not a login prompt, so a draft's
existence isn't revealed. Authenticated -> renders normally. No separate
login flow needed - Basic Auth credentials are scoped to the whole
origin/realm, so authenticating once at /admin covers draft URLs too.

AdminAuth::isAuthenticated() is extracted out of requireLogin() so the
draft gate can reuse the same credential check with a different failure
response (404 vs. a 401 challenge).

Renderer::render() gains an $excludeFromCache param so a draft without
its own sidecar can't get written to the static HTML cache - .htaccess
serves a cached file before PHP, and therefore any auth check, ever runs
again, so an uncached exception is required, not just the auth gate.

While testing this, found the same bug already existed for /admin itself:
novaconium/pages/admin/index.twig has no sidecar, so it was already being
cached - meaning any admin visiting /admin once caused the panel to be
served to everyone, unauthenticated, straight from
public/cache/admin/. Fixed in this change by excluding every /admin/*
route from the cache the same way, and documented as a standing rule in
AGENTS.md: any future mechanism that conditionally hides page content
from the public has to make the same check, not just gate the initial
request.

Closes the "Draft pages (admin-only preview)" backlog item in
novaconium/ISSUES.md.
2026-07-14 16:35:31 +00:00

46 lines
1.8 KiB
PHP

<?php
// Override any subset of novaconium/config.php's defaults here — only list
// the keys you want to change. novaconium/bootstrap.php (and
// novaconium/bin/clear-cache.php) shallow-merge this over the framework
// defaults; see /admin/docs/config. Uncomment and adjust any of the
// examples below, or leave this file returning an empty array to keep
// every framework default as-is.
return [
// 'debug' => false,
// 'site_name' => 'My Site',
// Docs: /admin/docs/matomo
// 'matomo_url' => 'https://matomo.example.com/',
// 'matomo_site_id' => '1',
// Docs: /admin/docs/admin-auth — generate a hash with:
// php -r "echo password_hash('yourpassword', PASSWORD_DEFAULT), PHP_EOL;"
// or use the built-in /admin/password-hash form.
// 'admin_username' => 'admin',
// 'admin_password_hash' => '$2y$10$...',
// Docs: /admin/docs/database — adds (or overrides) named Lib\Db
// connections. This merges into db_connections by name rather than
// replacing the whole map, so adding 'legacy' here doesn't require
// repeating 'default' — see Lib\Db::config().
// 'db_connections' => [
// 'legacy' => [
// 'driver' => 'mysql',
// 'host' => 'localhost',
// 'port' => 3306,
// 'database' => 'legacy_app',
// 'username' => 'root',
// 'password' => '...',
// 'charset' => 'utf8mb4', // optional, defaults to utf8mb4
// 'migrations_dir' => __DIR__ . '/migrations/legacy', // optional
// ],
// ],
// Docs: /admin/docs/drafts — requires admin_password_hash above to be
// set to actually gate anything; open access otherwise, same as the
// rest of /admin/*.
// 'draft_routes' => ['blog/upcoming-post'],
];