From ddd81d73e780fb2e563c260f763e69e800575b3f Mon Sep 17 00:00:00 2001 From: Myron Blair Date: Tue, 9 Jun 2026 18:42:23 +0000 Subject: [PATCH] Fix MySQL create: sanitize db names, fix empty db_user default, catch RuntimeException Dots/dashes in names were failing validateName; now stripped to underscores. Empty db_user field sent as "" (not null) so ?? fallback never fired; fixed to check for empty string explicitly. Wrap createMySQL/Postgres in try/catch so validation errors return 400 JSON instead of 500. Also pass db_type from JS (was being sent as db_type not type). Co-Authored-By: Claude Sonnet 4.6 --- panel/api/endpoints/databases.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/panel/api/endpoints/databases.php b/panel/api/endpoints/databases.php index a18a358..908da4a 100644 --- a/panel/api/endpoints/databases.php +++ b/panel/api/endpoints/databases.php @@ -38,9 +38,10 @@ match ($action) { } // Default to active DB engine from settings so autoinstallers use whatever the admin has selected $activeEngine = $db->fetchOne("SELECT `value` FROM settings WHERE `key`='active_db_engine'")['value'] ?? 'mysql'; - $type = $body['type'] ?? ($activeEngine === 'postgresql' ? 'postgresql' : 'mysql'); - $dbName = trim($body['db_name'] ?? ''); - $dbUser = trim($body['db_user'] ?? $dbName . '_user'); + $type = $body['type'] ?? $body['db_type'] ?? ($activeEngine === 'postgresql' ? 'postgresql' : 'mysql'); + $dbName = preg_replace('/[^a-zA-Z0-9_]/', '_', trim($body['db_name'] ?? '')); + $rawUser = trim($body['db_user'] ?? ''); + $dbUser = $rawUser !== '' ? preg_replace('/[^a-zA-Z0-9_]/', '_', $rawUser) : ''; $dbPass = $body['db_pass'] ?? bin2hex(random_bytes(8)); if (!$dbName) Response::error("db_name required"); @@ -48,11 +49,20 @@ match ($action) { $acct = $db->fetchOne("SELECT username FROM accounts WHERE id = ?", [$accountId]); $prefix = $acct['username'] . '_'; if (!str_starts_with($dbName, $prefix)) $dbName = $prefix . $dbName; + // Default db_user from db_name if blank, then prefix + if ($dbUser === '') $dbUser = $dbName . '_user'; if (!str_starts_with($dbUser, $prefix)) $dbUser = $prefix . $dbUser; + // Enforce max length (MySQL username limit is 32, db name 64) + $dbName = substr($dbName, 0, 64); + $dbUser = substr($dbUser, 0, 32); - $id = $type === 'postgresql' - ? DatabaseManager::createPostgres($accountId, $dbName, $dbUser, $dbPass) - : DatabaseManager::createMySQL($accountId, $dbName, $dbUser, $dbPass); + try { + $id = $type === 'postgresql' + ? DatabaseManager::createPostgres($accountId, $dbName, $dbUser, $dbPass) + : DatabaseManager::createMySQL($accountId, $dbName, $dbUser, $dbPass); + } catch (RuntimeException $e) { + Response::error($e->getMessage()); + } audit('database.create', $dbName, ['type' => $type]); Response::success(['id' => $id, 'db_name' => $dbName, 'db_user' => $dbUser, 'db_pass' => $dbPass], 'Database created');