diff --git a/app/modules/cli/Commands/InstallCommand.php b/app/modules/cli/Commands/InstallCommand.php index 827484d9..e0debc03 100644 --- a/app/modules/cli/Commands/InstallCommand.php +++ b/app/modules/cli/Commands/InstallCommand.php @@ -51,28 +51,29 @@ final class InstallCommand extends CommandBase * @var string[] */ public static array $envVarsMapping = [ - 'adminLogin' => 'ADMIN_LOGIN', - 'adminPassword' => 'ADMIN_PASSWORD', - 'databaseHost' => 'DATABASE_HOST', - 'databaseName' => 'DATABASE_NAME', - 'databaseUser' => 'DATABASE_USER', + 'adminLogin' => 'ADMIN_LOGIN', + 'adminPassword' => 'ADMIN_PASSWORD', + 'databaseHost' => 'DATABASE_HOST', + 'databaseName' => 'DATABASE_NAME', + 'databaseUser' => 'DATABASE_USER', 'databasePassword' => 'DATABASE_PASSWORD', - 'masterPassword' => 'MASTER_PASSWORD', - 'hostingMode' => 'HOSTING_MODE', - 'language' => 'LANGUAGE', - 'forceInstall' => 'FORCE_INSTALL', - 'install' => 'INSTALL' + 'masterPassword' => 'MASTER_PASSWORD', + 'hostingMode' => 'HOSTING_MODE', + 'language' => 'LANGUAGE', + 'forceInstall' => 'FORCE_INSTALL', + 'install' => 'INSTALL', ]; /** * @var string */ - protected static $defaultName = 'sp:install'; + protected static $defaultName = 'sp:install'; private Installer $installer; - public function __construct(LoggerInterface $logger, - Config $config, - Installer $installer) - { + public function __construct( + LoggerInterface $logger, + Config $config, + Installer $installer + ) { parent::__construct($logger, $config); $this->installer = $installer; @@ -82,53 +83,74 @@ final class InstallCommand extends CommandBase { $this->setDescription(__('Install sysPass')) ->setHelp(__('This command installs sysPass')) - ->addArgument('adminLogin', + ->addArgument( + 'adminLogin', InputArgument::OPTIONAL, - __('Admin user to log into the application')) - ->addArgument('databaseHost', + __('Admin user to log into the application') + ) + ->addArgument( + 'databaseHost', InputArgument::OPTIONAL, - __('Server name to install sysPass database')) - ->addArgument('databaseName', + __('Server name to install sysPass database') + ) + ->addArgument( + 'databaseName', InputArgument::OPTIONAL, - __('Application database name. eg. syspass')) - ->addArgument('databaseUser', + __('Application database name. eg. syspass') + ) + ->addArgument( + 'databaseUser', InputArgument::OPTIONAL, - __('An user with database administrative rights')) - ->addOption('databasePassword', + __('An user with database administrative rights') + ) + ->addOption( + 'databasePassword', null, InputOption::VALUE_OPTIONAL, - __('Database administrator\'s password')) - ->addOption('adminPassword', + __('Database administrator\'s password') + ) + ->addOption( + 'adminPassword', null, InputOption::VALUE_OPTIONAL, - __('Application administrator\'s password')) - ->addOption('masterPassword', + __('Application administrator\'s password') + ) + ->addOption( + 'masterPassword', null, InputOption::VALUE_OPTIONAL, - __('Master password to encrypt the data')) - ->addOption('hostingMode', + __('Master password to encrypt the data') + ) + ->addOption( + 'hostingMode', null, InputOption::VALUE_NONE, - __('It does not create or verify the user\'s permissions on the DB')) - ->addOption('language', + __('It does not create or verify the user\'s permissions on the DB') + ) + ->addOption( + 'language', null, InputOption::VALUE_OPTIONAL, - __('Sets the global app language. You can set a per user language on preferences')) - ->addOption('forceInstall', + __('Sets the global app language. You can set a per user language on preferences') + ) + ->addOption( + 'forceInstall', null, InputOption::VALUE_NONE, - __('Force sysPass installation')) - ->addOption('install', + __('Force sysPass installation') + ) + ->addOption( + 'install', null, InputOption::VALUE_NONE, - __('Skip asking to confirm the installation')); + __('Skip asking to confirm the installation') + ); } protected function execute( - InputInterface $input, + InputInterface $input, OutputInterface $output - ): int - { + ): int { $style = new SymfonyStyle($input, $output); try { @@ -143,7 +165,7 @@ final class InstallCommand extends CommandBase return self::FAILURE; } - $this->installer->run($installData); + $this->installer->run(Installer::getDatabaseSetup($installData, $this->configData), $installData); $this->logger->info(__('Installation finished')); @@ -174,8 +196,7 @@ final class InstallCommand extends CommandBase private function getInstallData( InputInterface $input, StyleInterface $style - ): InstallData - { + ): InstallData { $adminPassword = $this->getAdminPassword($input, $style); $masterPassword = $this->getMasterPassword($input, $style); $databasePassword = $this->getDatabasePassword($input, $style); @@ -207,8 +228,7 @@ final class InstallCommand extends CommandBase private function getAdminPassword( InputInterface $input, StyleInterface $style - ) - { + ) { $option = 'adminPassword'; $password = @@ -236,7 +256,9 @@ final class InstallCommand extends CommandBase if ($password !== $passwordRepeat) { throw new InstallError(__u('Passwords do not match')); - } elseif (null === $password || null === $passwordRepeat) { + } + + if (null === $password || null === $passwordRepeat) { throw new InstallError(sprintf(__u('%s cannot be blank'), 'Admin password')); } } @@ -252,8 +274,7 @@ final class InstallCommand extends CommandBase private function getMasterPassword( InputInterface $input, StyleInterface $style - ) - { + ) { $password = self::getEnvVarOrOption('masterPassword', $input); if (empty($password)) { @@ -276,7 +297,9 @@ final class InstallCommand extends CommandBase if ($password !== $passwordRepeat) { throw new InstallError(__u('Passwords do not match')); - } elseif (null === $password || null === $passwordRepeat) { + } + + if (null === $password || null === $passwordRepeat) { throw new InstallError(sprintf(__u('%s cannot be blank'), 'Master password')); } } @@ -290,8 +313,7 @@ final class InstallCommand extends CommandBase private function getDatabasePassword( InputInterface $input, StyleInterface $style - ) - { + ) { $password = self::getEnvVarOrOption('databasePassword', $input); if (empty($password)) { @@ -309,8 +331,7 @@ final class InstallCommand extends CommandBase private function getLanguage( InputInterface $input, StyleInterface $style - ) - { + ) { $language = self::getEnvVarOrOption('language', $input); if (empty($language)) { @@ -360,8 +381,7 @@ final class InstallCommand extends CommandBase private function getInstall( InputInterface $input, StyleInterface $style - ): bool - { + ): bool { $option = 'install'; $envInstall = self::getEnvVarForOption($option); diff --git a/app/modules/web/Controllers/InstallController.php b/app/modules/web/Controllers/InstallController.php index 76462f0c..5d5ba442 100644 --- a/app/modules/web/Controllers/InstallController.php +++ b/app/modules/web/Controllers/InstallController.php @@ -129,7 +129,7 @@ final class InstallController extends ControllerBase $installData->setHostingMode($this->request->analyzeBool('hostingmode', false)); try { - $this->installer->run($installData); + $this->installer->run(Installer::getDatabaseSetup($installData, $this->configData), $installData); return $this->returnJsonResponse( JsonResponse::JSON_SUCCESS, diff --git a/lib/SP/Services/Install/Installer.php b/lib/SP/Services/Install/Installer.php index c0e14282..bd3f0236 100644 --- a/lib/SP/Services/Install/Installer.php +++ b/lib/SP/Services/Install/Installer.php @@ -44,6 +44,8 @@ use SP\Services\Config\ConfigService; use SP\Services\User\UserService; use SP\Services\UserGroup\UserGroupService; use SP\Services\UserProfile\UserProfileService; +use SP\Storage\Database\DatabaseConnectionData; +use SP\Storage\Database\MySQLHandler; use SP\Util\VersionUtil; defined('APP_ROOT') || die(); @@ -60,17 +62,16 @@ final class Installer public const VERSION_TEXT = '3.2'; public const BUILD = 21031301; - private DatabaseSetupInterface $databaseSetup; - private Request $request; - private Config $config; - private UserService $userService; - private UserGroupService $userGroupService; - private UserProfileService $userProfileService; - private ConfigService $configService; - private ?InstallData $installData = null; + private Request $request; + private Config $config; + private UserService $userService; + private UserGroupService $userGroupService; + private UserProfileService $userProfileService; + private ConfigService $configService; + private ?DatabaseSetupInterface $databaseSetup = null; + private ?InstallData $installData = null; public function __construct( - DatabaseSetupInterface $databaseSetup, Request $request, Config $config, UserService $userService, @@ -78,7 +79,6 @@ final class Installer UserProfileService $userProfileService, ConfigService $configService ) { - $this->databaseSetup = $databaseSetup; $this->request = $request; $this->config = $config; $this->userService = $userService; @@ -87,13 +87,33 @@ final class Installer $this->configService = $configService; } + /** + * @param \SP\Services\Install\InstallData $installData + * @param $configData + * + * @return \SP\Services\Install\DatabaseSetupInterface + * @throws \SP\Core\Exceptions\SPException + */ + public static function getDatabaseSetup(InstallData $installData, $configData): DatabaseSetupInterface + { + $connectionData = (new DatabaseConnectionData()) + ->setDbHost($installData->getDbHost()) + ->setDbPort($installData->getDbPort()) + ->setDbSocket($installData->getDbSocket()) + ->setDbUser($installData->getDbAdminUser()) + ->setDbPass($installData->getDbAdminPass()); + + return new MySQL(new MySQLHandler($connectionData), $installData, $configData); + } + /** * @throws InvalidArgumentException * @throws SPException */ - public function run(InstallData $installData): Installer + public function run(DatabaseSetupInterface $databaseSetup, InstallData $installData): Installer { + $this->databaseSetup = $databaseSetup; $this->installData = $installData; $this->checkData(); diff --git a/tests/SP/Services/Install/InstallerTest.php b/tests/SP/Services/Install/InstallerTest.php index a6893fa8..5451fc23 100644 --- a/tests/SP/Services/Install/InstallerTest.php +++ b/tests/SP/Services/Install/InstallerTest.php @@ -92,7 +92,7 @@ class InstallerTest extends UnitaryTestCase $installer = $this->getDefaultInstaller(); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); $configData = $this->config->getConfigData(); @@ -133,7 +133,6 @@ class InstallerTest extends UnitaryTestCase private function getDefaultInstaller(): Installer { return new Installer( - $this->mysqlSetup, $this->request, $this->config, $this->userService, @@ -160,7 +159,7 @@ class InstallerTest extends UnitaryTestCase $installer = $this->getDefaultInstaller(); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); $configData = $this->config->getConfigData(); @@ -185,7 +184,7 @@ class InstallerTest extends UnitaryTestCase $installer = $this->getDefaultInstaller(); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); $this->assertEquals($params->getDbHost(), $params->getDbAuthHost()); } @@ -206,7 +205,7 @@ class InstallerTest extends UnitaryTestCase $installer = $this->getDefaultInstaller(); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); $this->assertEquals(SELF_IP_ADDRESS, $params->getDbAuthHost()); $this->assertEquals('host', $params->getDbHost()); @@ -227,7 +226,7 @@ class InstallerTest extends UnitaryTestCase $installer = $this->getDefaultInstaller(); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); $configData = $this->config->getConfigData(); @@ -252,7 +251,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(SPException::class); $this->expectExceptionMessage('Error while creating \'admin\' user'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -273,7 +272,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(SPException::class); $this->expectExceptionMessage('Create exception'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -290,7 +289,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Please, enter the admin username'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -307,7 +306,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Please, enter the admin\'s password'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -324,7 +323,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Please, enter the Master Password'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -341,7 +340,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Master password too short'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -358,7 +357,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Please, enter the database user'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -375,7 +374,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Please, enter the database password'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -392,7 +391,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Please, enter the database name'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -409,7 +408,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Database name cannot contain "."'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @@ -426,7 +425,7 @@ class InstallerTest extends UnitaryTestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Please, enter the database server'); - $installer->run($params); + $installer->run($this->mysqlSetup, $params); } /** @noinspection ClassMockingCorrectnessInspection