From dd3af291b2a9b56d8be996b27264321ef3e828d4 Mon Sep 17 00:00:00 2001 From: Stefan Giehl Date: Mon, 27 May 2024 15:56:48 +0200 Subject: [PATCH] Improve handling of database port during installation process (#22252) * Allow providing database port during installation * don't reveal already provided password during installation * Revert using an additional field for host * apply review feedback --- core/Db/Adapter.php | 3 +- core/Db/Adapter/Mysqli.php | 1 + core/Db/Adapter/Pdo/Mysql.php | 1 + core/Db/AdapterInterface.php | 1 + core/Db/Schema.php | 13 +++++ core/Db/Schema/Mysql.php | 5 ++ core/Db/Schema/Tidb.php | 5 ++ core/Db/SchemaInterface.php | 7 +++ .../Diagnostics/Diagnostic/DbAdapterCheck.php | 2 +- plugins/Installation/FormDatabaseSetup.php | 51 ++++++++++++++----- 10 files changed, 74 insertions(+), 15 deletions(-) diff --git a/core/Db/Adapter.php b/core/Db/Adapter.php index 3fd0c543881..79b9eeeb13b 100644 --- a/core/Db/Adapter.php +++ b/core/Db/Adapter.php @@ -89,6 +89,7 @@ private static function getAdapterClassName($adapterName) /** * Get default port for named adapter * + * @deprecated use Schema::getDefaultPortForSchema instead * @param string $adapterName * @return int */ @@ -118,7 +119,7 @@ public static function getAdapters() foreach ($adapterNames as $adapterName) { $className = '\Piwik\Db\Adapter\\' . $adapterName; if (call_user_func(array($className, 'isEnabled'))) { - $adapters[strtoupper($adapterName)] = call_user_func(array($className, 'getDefaultPort')); + $adapters[] = strtoupper($adapterName); } } diff --git a/core/Db/Adapter/Mysqli.php b/core/Db/Adapter/Mysqli.php index 99693a85f37..5dca6138b40 100644 --- a/core/Db/Adapter/Mysqli.php +++ b/core/Db/Adapter/Mysqli.php @@ -70,6 +70,7 @@ public function resetConfig() /** * Return default port. * + * @deprecated Use Schema::getDefaultPortForSchema instead * @return int */ public static function getDefaultPort() diff --git a/core/Db/Adapter/Pdo/Mysql.php b/core/Db/Adapter/Pdo/Mysql.php index a640fa41eab..b36927e4e80 100644 --- a/core/Db/Adapter/Pdo/Mysql.php +++ b/core/Db/Adapter/Pdo/Mysql.php @@ -136,6 +136,7 @@ public function resetConfig() /** * Return default port. * + * @deprecated Use Schema::getDefaultPortForSchema instead * @return int */ public static function getDefaultPort() diff --git a/core/Db/AdapterInterface.php b/core/Db/AdapterInterface.php index 4c22a173178..18debd257e4 100644 --- a/core/Db/AdapterInterface.php +++ b/core/Db/AdapterInterface.php @@ -22,6 +22,7 @@ public function resetConfig(); /** * Return default port. + * @deprecated Use Schema::getDefaultPortForSchema instead * * @return int */ diff --git a/core/Db/Schema.php b/core/Db/Schema.php index 76df7e05db9..08a044633f2 100644 --- a/core/Db/Schema.php +++ b/core/Db/Schema.php @@ -48,6 +48,19 @@ private static function getSchemaClassName($schemaName): string return '\Piwik\Db\Schema\\' . $class; } + /** + * Return the default port for the provided database schema + * + * @param string $schemaName + * @return int + */ + public static function getDefaultPortForSchema(string $schemaName): int + { + $schemaClassName = self::getSchemaClassName($schemaName); + /** @var SchemaInterface $schemaClass */ + $schemaClass = new $schemaClassName(); + return $schemaClass->getDefaultPort(); + } /** * Load schema diff --git a/core/Db/Schema/Mysql.php b/core/Db/Schema/Mysql.php index 9c22fca442a..8d6cf008c11 100644 --- a/core/Db/Schema/Mysql.php +++ b/core/Db/Schema/Mysql.php @@ -675,6 +675,11 @@ public function supportsComplexColumnUpdates(): bool return true; } + public function getDefaultPort(): int + { + return 3306; + } + private function getTablePrefix() { return $this->getDbSettings()->getTablePrefix(); diff --git a/core/Db/Schema/Tidb.php b/core/Db/Schema/Tidb.php index a4bde90ba09..6a1f1e29a27 100644 --- a/core/Db/Schema/Tidb.php +++ b/core/Db/Schema/Tidb.php @@ -24,4 +24,9 @@ public function supportsComplexColumnUpdates(): bool { return false; } + + public function getDefaultPort(): int + { + return 4000; + } } diff --git a/core/Db/SchemaInterface.php b/core/Db/SchemaInterface.php index f59308b99d4..6405c1260d2 100644 --- a/core/Db/SchemaInterface.php +++ b/core/Db/SchemaInterface.php @@ -124,4 +124,11 @@ public function addMaxExecutionTimeHintToQuery(string $sql, float $limit): strin * @return bool */ public function supportsComplexColumnUpdates(): bool; + + /** + * Return the default port used by this database engine + * + * @return int + */ + public function getDefaultPort(): int; } diff --git a/plugins/Diagnostics/Diagnostic/DbAdapterCheck.php b/plugins/Diagnostics/Diagnostic/DbAdapterCheck.php index 6af12b8b8fe..7fe0f0b00d2 100644 --- a/plugins/Diagnostics/Diagnostic/DbAdapterCheck.php +++ b/plugins/Diagnostics/Diagnostic/DbAdapterCheck.php @@ -55,7 +55,7 @@ private function checkDbAdapters() $results = array(); $adapters = Adapter::getAdapters(); - foreach ($adapters as $adapter => $port) { + foreach ($adapters as $adapter) { $label = $adapter . ' ' . $this->translator->translate('Installation_Extension'); $results[] = DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_OK); diff --git a/plugins/Installation/FormDatabaseSetup.php b/plugins/Installation/FormDatabaseSetup.php index d5b795e675e..97c7e744604 100644 --- a/plugins/Installation/FormDatabaseSetup.php +++ b/plugins/Installation/FormDatabaseSetup.php @@ -27,6 +27,8 @@ */ class FormDatabaseSetup extends QuickForm2 { + const MASKED_PASSWORD_VALUE = '**********'; + function __construct($id = 'databasesetupform', $method = 'post', $attributes = null, $trackSubmit = false) { parent::__construct($id, $method, $attributes = array('autocomplete' => 'off'), $trackSubmit); @@ -46,7 +48,7 @@ function init() $availableAdapters = Adapter::getAdapters(); $adapters = array(); - foreach ($availableAdapters as $adapter => $port) { + foreach ($availableAdapters as $adapter) { $adapters[$adapter] = $adapter; if (Adapter::isRecommendedAdapter($adapter)) { $adapters[$adapter] .= ' (' . Piwik::translate('General_Recommended') . ')'; @@ -98,23 +100,39 @@ function init() 'type' => $defaultDatabaseType, 'tables_prefix' => 'matomo_', 'schema' => 'Mysql', + 'port' => '3306', ); $defaultsEnvironment = array('host', 'adapter', 'tables_prefix', 'username', 'schema', 'password', 'dbname'); foreach ($defaultsEnvironment as $name) { - $envName = 'DATABASE_' . strtoupper($name); // fyi getenv is case insensitive - $envNameMatomo = 'MATOMO_' . $envName; - if (getenv($envNameMatomo)) { - $defaults[$name] = getenv($envNameMatomo); - } elseif (getenv($envName)) { - $defaults[$name] = getenv($envName); + $envValue = $this->getEnvironmentSetting($name); + + if (null !== $envValue) { + $defaults[$name] = $envValue; } } + if (array_key_exists('password', $defaults)) { + $defaults['password'] = self::MASKED_PASSWORD_VALUE; // ensure not to show password in UI + } + // default values $this->addDataSource(new HTML_QuickForm2_DataSource_Array($defaults)); } + private function getEnvironmentSetting(string $name): ?string + { + $envName = 'DATABASE_' . strtoupper($name); // fyi getenv is case insensitive + $envNameMatomo = 'MATOMO_' . $envName; + if (is_string(getenv($envNameMatomo))) { + return getenv($envNameMatomo); + } elseif (is_string(getenv($envName))) { + return getenv($envName); + } + + return null; + } + /** * Creates database object based on form data. * @@ -130,20 +148,27 @@ public function createDatabaseObject() } $adapter = $this->getSubmitValue('adapter'); - $port = Adapter::getDefaultPortForAdapter($adapter); - $host = $this->getSubmitValue('host'); $tables_prefix = $this->getSubmitValue('tables_prefix'); - + + $password = $this->getSubmitValue('password'); + $passwordFromEnv = $this->getEnvironmentSetting('password'); + + if ($password === self::MASKED_PASSWORD_VALUE && null !== $passwordFromEnv) { + $password = $passwordFromEnv; + } + + $schema = $this->getSubmitValue('schema'); + $dbInfos = array( 'host' => (is_null($host)) ? $host : trim($host), 'username' => $this->getSubmitValue('username'), - 'password' => $this->getSubmitValue('password'), + 'password' => $password, 'dbname' => $dbname, 'tables_prefix' => (is_null($tables_prefix)) ? $tables_prefix : trim($tables_prefix), 'adapter' => $adapter, - 'port' => $port, - 'schema' => $this->getSubmitValue('schema'), + 'port' => Db\Schema::getDefaultPortForSchema($schema), + 'schema' => $schema, 'type' => $this->getSubmitValue('type'), 'enable_ssl' => false );