From d3a537aa6c2783cd58d4d6eccf0c296b6cca6d41 Mon Sep 17 00:00:00 2001 From: Greg Sarjeant Date: Wed, 13 Aug 2025 12:02:37 +0000 Subject: [PATCH] Fix first-time setup issues. (#68) Fixes for issues found testing first time setup in the different configurations. Reviewed-on: https://gitea.subcultureofone.org/greg/tkr/pulls/68 Co-authored-by: Greg Sarjeant Co-committed-by: Greg Sarjeant --- .gitignore | 3 +- config/bootstrap.php | 4 +++ docker/apache/shared-hosting/.htaccess | 3 ++ .../apache/shared-hosting/docker-compose.yml | 1 + docker/apache/vps/root/docker-compose.yml | 1 + .../apache/vps/subfolder/docker-compose.yml | 1 + docker/nginx/root/docker-compose.yml | 1 + docker/nginx/subfolder/docker-compose.yml | 1 + examples/apache/shared-hosting/.htaccess | 3 ++ public/index.php | 16 ++++++--- .../CssController/CssController.php | 2 +- src/Framework/Prerequisites/Prerequisites.php | 14 ++++---- src/Framework/Session/Session.php | 9 +++++ src/Framework/Util/Util.php | 12 ++++--- templates/partials/admin.php | 36 ++++++++++--------- tkr-setup.php | 3 +- 16 files changed, 77 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 7ca5f92..95301b4 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,10 @@ storage/logs # Testing stuff /docker-compose.yml scratch +storage.bak # Build artifacts tkr.tgz # Test logs -storage/prerequisite-check.log \ No newline at end of file +storage/prerequisite-check.log diff --git a/config/bootstrap.php b/config/bootstrap.php index 363f9c4..c3f5d09 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -5,6 +5,10 @@ declare(strict_types=1); // - define paths // - set up autoloader +// Set a couple ini settings for security +ini_set('allow_url_fopen', 0); // don't allow remote files to be read +ini_set('expose_php', 0); // don't advertise the PHP version + // Define all the important paths define('APP_ROOT', dirname(dirname(__FILE__))); // Root-level directories diff --git a/docker/apache/shared-hosting/.htaccess b/docker/apache/shared-hosting/.htaccess index c2bf33a..71f8f55 100644 --- a/docker/apache/shared-hosting/.htaccess +++ b/docker/apache/shared-hosting/.htaccess @@ -13,6 +13,9 @@ RewriteRule ^(storage|src|templates|config)(/.*)?$ - [F,L] # Block access to hidden files RewriteRule ^\..*$ - [F,L] +# Block access to setup script +RewriteRule ^tkr-setup\.php$ - [F,L] + # Route everything else through public/index.php RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d diff --git a/docker/apache/shared-hosting/docker-compose.yml b/docker/apache/shared-hosting/docker-compose.yml index 0c5e22d..22347d5 100644 --- a/docker/apache/shared-hosting/docker-compose.yml +++ b/docker/apache/shared-hosting/docker-compose.yml @@ -10,6 +10,7 @@ services: - ./src:/var/www/html/tkr/src - ./storage:/var/www/html/tkr/storage - ./templates:/var/www/html/tkr/templates + - ./tkr-setup.php:/var/www/html/tkr/tkr-setup.php - ./docker/apache/shared-hosting/.htaccess:/var/www/html/tkr/.htaccess command: > bash -c "a2enmod rewrite headers expires && diff --git a/docker/apache/vps/root/docker-compose.yml b/docker/apache/vps/root/docker-compose.yml index a7d1d9e..1c33b21 100644 --- a/docker/apache/vps/root/docker-compose.yml +++ b/docker/apache/vps/root/docker-compose.yml @@ -10,6 +10,7 @@ services: - ./src:/var/www/tkr/src - ./storage:/var/www/tkr/storage - ./templates:/var/www/tkr/templates + - ./tkr-setup.php:/var/www/html/tkr/tkr-setup.php - ./docker/apache/vps/root/tkr.my-domain.com.conf:/etc/apache2/sites-enabled/tkr.my-domain.com.conf command: > bash -c "a2enmod rewrite headers expires && diff --git a/docker/apache/vps/subfolder/docker-compose.yml b/docker/apache/vps/subfolder/docker-compose.yml index b227422..5a3a30e 100644 --- a/docker/apache/vps/subfolder/docker-compose.yml +++ b/docker/apache/vps/subfolder/docker-compose.yml @@ -10,6 +10,7 @@ services: - ./src:/var/www/tkr/src - ./storage:/var/www/tkr/storage - ./templates:/var/www/tkr/templates + - ./tkr-setup.php:/var/www/html/tkr/tkr-setup.php - ./docker/apache/vps/subfolder/my-domain.com.conf:/etc/apache2/sites-enabled/my-domain.com.conf command: > bash -c "a2enmod rewrite headers expires && diff --git a/docker/nginx/root/docker-compose.yml b/docker/nginx/root/docker-compose.yml index 0d0d9ab..eff3cab 100644 --- a/docker/nginx/root/docker-compose.yml +++ b/docker/nginx/root/docker-compose.yml @@ -20,6 +20,7 @@ services: - ./src:/var/www/tkr/src - ./storage:/var/www/tkr/storage - ./templates:/var/www/tkr/templates + - ./tkr-setup.php:/var/www/html/tkr/tkr-setup.php command: > sh -c " chown -R www-data:www-data /var/www/tkr/storage && diff --git a/docker/nginx/subfolder/docker-compose.yml b/docker/nginx/subfolder/docker-compose.yml index a7cedaf..bc9de37 100644 --- a/docker/nginx/subfolder/docker-compose.yml +++ b/docker/nginx/subfolder/docker-compose.yml @@ -20,6 +20,7 @@ services: - ./src:/var/www/tkr/src - ./storage:/var/www/tkr/storage - ./templates:/var/www/tkr/templates + - ./tkr-setup.php:/var/www/html/tkr/tkr-setup.php command: > sh -c " chown -R www-data:www-data /var/www/tkr/storage && diff --git a/examples/apache/shared-hosting/.htaccess b/examples/apache/shared-hosting/.htaccess index 65e699e..b41af00 100644 --- a/examples/apache/shared-hosting/.htaccess +++ b/examples/apache/shared-hosting/.htaccess @@ -14,6 +14,9 @@ RewriteRule ^(storage|src|templates|config)(/.*)?$ - [F,L] # Block access to hidden files RewriteRule ^\..*$ - [F,L] +# Block access to setup script +RewriteRule ^tkr-setup\.php$ - [F,L] + # Route everything else through the front controller RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d diff --git a/public/index.php b/public/index.php index eb1a8a0..f8dd5e8 100644 --- a/public/index.php +++ b/public/index.php @@ -49,7 +49,8 @@ if (!$prerequisites->applyMigrations($db)){ } // Check if setup is complete (user exists and URL is configured) -if (!(preg_match('/tkr-setup$/', $path))) { +// Skip the setup check for the default css +if (!(preg_match('/tkr-setup$/', $path) || preg_match('/default.css$/', $path))) { try { $user_count = (int) $db->query("SELECT COUNT(*) FROM user")->fetchColumn(); $settings = (new SettingsModel($db))->get(); @@ -72,6 +73,10 @@ if (!(preg_match('/tkr-setup$/', $path))) { echo "

Please check your installation or contact your hosting provider.

"; exit; } +} else { + // we're heading to setup. the base path hasn't been set. autodetect it + $autodetected = Util::getAutodetectedUrl(); + $basePath = $autodetected['basePath']; } /* @@ -92,8 +97,11 @@ Session::start(); Session::generateCsrfToken(); // Remove the base path from the URL -if (strpos($path, $app['settings']->basePath) === 0) { - $path = substr($path, strlen($app['settings']->basePath)); +// If basePath isn't already set (i.e. we're not autodetecting it en route to tkr-setup), +// set it to the value from settings +$basePath ??= $app['settings']->basePath; +if (strpos($path, $basePath) === 0) { + $path = substr($path, strlen($basePath)); } // strip the trailing slash from the resulting route @@ -106,7 +114,7 @@ Log::debug("Path requested: {$path}"); // if this is a POST and we aren't in setup, // make sure there's a valid session // if not, redirect to /login or die as appropriate -if ($method === 'POST' && $path != 'setup') { +if ($method === 'POST' && $path != 'tkr-setup') { if ($path != 'login'){ if (!Session::isValid($_POST['csrf_token'])) { // Invalid session - redirect to /login diff --git a/src/Controller/CssController/CssController.php b/src/Controller/CssController/CssController.php index cbe8483..05c94fc 100644 --- a/src/Controller/CssController/CssController.php +++ b/src/Controller/CssController/CssController.php @@ -100,7 +100,7 @@ class CssController extends Controller { } // Get the data for the selected CSS file - $cssId = $_POST['selectCssFile']; + $cssId = (int) $_POST['selectCssFile']; $cssModel = new CssModel($app['db']); $cssRow = $cssModel->getById($cssId); diff --git a/src/Framework/Prerequisites/Prerequisites.php b/src/Framework/Prerequisites/Prerequisites.php index 27b31d9..b9f7a60 100644 --- a/src/Framework/Prerequisites/Prerequisites.php +++ b/src/Framework/Prerequisites/Prerequisites.php @@ -407,7 +407,7 @@ class Prerequisites { } } - private function createDatabase() { + private function createDatabase(): bool { $dbFile = $this->baseDir . '/storage/db/tkr.sqlite'; // Test database connection (will create file if needed) @@ -442,7 +442,7 @@ class Prerequisites { } } - public function applyMigrations($db) { + public function applyMigrations($db): bool { try { $migrator = new Migrator($db); $migrator->migrate(); @@ -452,8 +452,6 @@ class Prerequisites { true, 'All database migrations applied successfully' ); - return true; - } catch (Exception $e) { $this->addCheck( 'Database Migrations', @@ -463,6 +461,8 @@ class Prerequisites { ); return false; } + + return true; } // Validate system requirements that can't be fixed by the script @@ -511,6 +511,8 @@ class Prerequisites { // Create missing application components public function createMissing(): bool { + // If we're calling this, there were likely setup validation errors + $currentErrors = count($this->errors); $this->log("=== tkr setup started at " . date('Y-m-d H:i:s') . " ===", true); if ($this->isCli) { @@ -526,8 +528,8 @@ class Prerequisites { $this->generateCliSummary($results); } - // Return true only if no errors occurred - return count($this->errors) === 0; + // Return true only if no NEW errors occurred + return count($this->errors) === $currentErrors; } /** diff --git a/src/Framework/Session/Session.php b/src/Framework/Session/Session.php index bf256af..bff3b9a 100644 --- a/src/Framework/Session/Session.php +++ b/src/Framework/Session/Session.php @@ -7,6 +7,15 @@ class Session { // global $_SESSION associative array public static function start(): void{ if (session_status() === PHP_SESSION_NONE) { + // Cookie security settings + ini_set('session.cookie_httponly', 1); + ini_set('session.cookie_samesite', 'Strict'); + + // Enable secure cookie flag if HTTPS is being used + if (($_SERVER['HTTPS'] ?? 'off') === 'on') { + ini_set('session.cookie_secure', 1); + } + $existingSessionId = $_COOKIE['PHPSESSID'] ?? null; session_start(); diff --git a/src/Framework/Util/Util.php b/src/Framework/Util/Util.php index 0af9f5d..2091d5a 100644 --- a/src/Framework/Util/Util.php +++ b/src/Framework/Util/Util.php @@ -125,6 +125,13 @@ class Util { $scriptName = $_SERVER['SCRIPT_NAME'] ?? '/index.php'; $basePath = dirname($scriptName); + // Handle shared hosting scenario where document root can't be set to public/ + // If script name ends with /public/index.php, we need to go up one directory + if (str_ends_with($scriptName, '/public/index.php')) { + $basePath = dirname($basePath); + } + + # Ensure base path always has a trailing / if ($basePath === '/' || $basePath === '.' || $basePath === '') { $basePath = '/'; } else { @@ -132,10 +139,7 @@ class Util { } // Construct full URL - $fullUrl = $baseUrl; - if ($basePath !== '/') { - $fullUrl .= ltrim($basePath, '/'); - } + $fullUrl = $baseUrl . $basePath; return [ 'baseUrl' => $baseUrl, diff --git a/templates/partials/admin.php b/templates/partials/admin.php index 387ffe0..0c112f1 100644 --- a/templates/partials/admin.php +++ b/templates/partials/admin.php @@ -1,12 +1,16 @@ -

SetupAdmin

+ +

- +
User settings
@@ -14,19 +18,19 @@ + value="website) ?>">
@@ -36,36 +40,36 @@ + value="siteDescription) ?>"> + value="tickDeleteHours ?? 1) ?>" min="1"> strictAccessibility): ?> checked >
diff --git a/tkr-setup.php b/tkr-setup.php index 676af17..ac14ee1 100644 --- a/tkr-setup.php +++ b/tkr-setup.php @@ -177,6 +177,7 @@ try { // Create/update settings $settingsModel = new SettingsModel($db); $settingsModel->siteTitle = $siteTitle; + $settingsModel->siteDescription = $siteTitle; $settingsModel->baseUrl = $baseUrl; $settingsModel->basePath = $basePath; $settings = $settingsModel->save(); @@ -184,7 +185,7 @@ try { // Create admin user $userModel = new UserModel($db); $userModel->username = $adminUsername; - $userModel->display_name = $adminUsername; + $userModel->displayName = $adminUsername; $userModel->website = ''; $userModel->mood = ''; $user = $userModel->save();