diff --git a/bin/froxlor-cli b/bin/froxlor-cli index b7e6d566..bc4f8835 100755 --- a/bin/froxlor-cli +++ b/bin/froxlor-cli @@ -35,6 +35,7 @@ use Froxlor\Cli\UpdateCommand; use Froxlor\Cli\InstallCommand; use Froxlor\Cli\MasterCron; use Froxlor\Cli\UserCommand; +use Froxlor\Cli\ValidateAcmeWebroot; use Froxlor\Froxlor; // validate correct php version @@ -59,4 +60,5 @@ $application->add(new UpdateCommand()); $application->add(new InstallCommand()); $application->add(new MasterCron()); $application->add(new UserCommand()); +$application->add(new ValidateAcmeWebroot()) $application->run(); diff --git a/customer_ftp.php b/customer_ftp.php index 77da795d..d5f3bd0f 100644 --- a/customer_ftp.php +++ b/customer_ftp.php @@ -40,7 +40,7 @@ use Froxlor\UI\Response; use Froxlor\CurrentUser; // redirect if this customer page is hidden via settings -if (Settings::IsInList('panel.customer_hide_options', 'ftp') || $userinfo['ftps'] == 0) { +if (Settings::IsInList('panel.customer_hide_options', 'ftp')) { Response::redirectTo('customer_index.php'); } diff --git a/lib/Froxlor/Cli/CliCommand.php b/lib/Froxlor/Cli/CliCommand.php index 8cc93a1c..e3dbe7f6 100644 --- a/lib/Froxlor/Cli/CliCommand.php +++ b/lib/Froxlor/Cli/CliCommand.php @@ -37,7 +37,7 @@ use Symfony\Component\Console\Output\OutputInterface; class CliCommand extends Command { - protected function validateRequirements(InputInterface $input, OutputInterface $output): int + protected function validateRequirements(InputInterface $input, OutputInterface $output, bool $ignore_has_updates = false): int { if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) { $output->writeln("Could not find froxlor's userdata.inc.php file. You should use this script only with an installed froxlor system."); @@ -51,7 +51,7 @@ class CliCommand extends Command $output->writeln("" . $e->getMessage() . ""); return self::INVALID; } - if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) { + if (!$ignore_has_updates && (Froxlor::hasUpdates() || Froxlor::hasDbUpdates())) { if ((int)Settings::Get('system.cron_allowautoupdate') == 1) { return $this->runUpdate($output); } else { diff --git a/lib/Froxlor/Cli/ValidateAcmeWebroot.php b/lib/Froxlor/Cli/ValidateAcmeWebroot.php new file mode 100644 index 00000000..678e2121 --- /dev/null +++ b/lib/Froxlor/Cli/ValidateAcmeWebroot.php @@ -0,0 +1,124 @@ + + * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 + */ + +namespace Froxlor\Cli; + +use Froxlor\Database\Database; +use Froxlor\FileDir; +use Froxlor\Froxlor; +use Froxlor\Settings; +use PDO; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ConfirmationQuestion; +use Symfony\Component\Console\Style\SymfonyStyle; + +final class ValidateAcmeWebroot extends CliCommand +{ + + protected function configure() + { + $this->setName('froxlor:validate-acme-webroot'); + $this->setDescription('Validates the Le_Webroot value is correct for froxlor managed domains with Let\s Encrypt certificate.'); + $this->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for confirmation, update files if necessary'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $result = self::SUCCESS; + + $result = $this->validateRequirements($input, $output, true); + + $io = new SymfonyStyle($input, $output); + + if ($result == self::SUCCESS) { + $yestoall = $input->getOption('yes-to-all') !== false; + $helper = $this->getHelper('question'); + $count_changes = 0; + // get all Let's Encrypt enabled domains + $sel_stmt = Database::prepare("SELECT id, domain FROM panel_domains WHERE `letsencrypt` = '1' ORDER BY id ASC"); + Database::pexecute($sel_stmt); + $domains = $sel_stmt->fetchAll(PDO::FETCH_ASSOC); + $upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET expirationdate=NULL WHERE `domainid` = :did"); + $acmesh_dir = dirname(Settings::Get('system.acmeshpath')); + $acmesh_challenge_dir = Settings::Get('system.letsencryptchallengepath'); + foreach ($domains as $domain_arr) { + $domain = $domain_arr['domain']; + $acme_domain_conf = FileDir::makeCorrectFile($acmesh_dir . '/' . $domain . '/' . $domain . '.conf'); + $conf_content = ""; + if (file_exists($acme_domain_conf)) { + $io->text("Getting info from " . $acme_domain_conf); + $conf_content = file_get_contents($acme_domain_conf); + } else { + $acme_domain_conf = FileDir::makeCorrectFile($acmesh_dir . '/' . $domain . '_ecc/' . $domain . '.conf'); + if (file_exists($acme_domain_conf)) { + $io->text("Getting info from " . $acme_domain_conf); + $conf_content = file_get_contents($acme_domain_conf); + } else { + $io->notice("No domain configuration file found in '" . $acmesh_dir . "'"); + break; + } + } + if (!empty($conf_content)) { + $lines = explode("\n", $conf_content); + foreach ($lines as $line) { + $val_key = explode("=", $line); + if ($val_key[0] == 'Le_Webroot') { + $domain_webroot = trim(trim($val_key[1], "'"), '"'); + if ($domain_webroot != $acmesh_challenge_dir) { + $io->warning("Domain '" . $domain . "' has old/wrong Le_Webroot setting: '" . $domain_webroot . ' <> ' . $acmesh_challenge_dir . "'"); + $question = new ConfirmationQuestion('Fix Le_Webroot? [yes] ', true, '/^(y|j)/i'); + if ($yestoall || $helper->ask($input, $output, $question)) { + $sed_params = "s@Le_Webroot=.*@Le_Webroot='" . $acmesh_challenge_dir . "'@"; + FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_domain_conf)); + Database::pexecute($upd_stmt, ['did' => $domain_arr['id']]); + $io->success("Correction of Le_Webroot successful"); + $count_changes++; + } else { + continue; + } + } else { + $io->info("Domain '" . $domain . "' Le_Webroot value is correct"); + } + break; + } else { + continue; + } + } + } + } + if ($count_changes > 0) { + $question = new ConfirmationQuestion('Changes detected. Force cronjob to refresh certificates? [yes] ', true, '/^(y|j)/i'); + if ($yestoall || $helper->ask($input, $output, $question)) { + passthru(FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -f -d'); + } + } + } + + return $result; + } + +}