notify_push/lib/Command/Setup.php

269 строки
10 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\NotifyPush\Command;
use OCA\NotifyPush\SetupWizard;
use OCP\IConfig;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class Setup extends Command {
private $test;
private $config;
private $setupWizard;
public function __construct(
\OCA\NotifyPush\SelfTest $test,
IConfig $config,
SetupWizard $setupWizard
) {
parent::__construct();
$this->test = $test;
$this->config = $config;
$this->setupWizard = $setupWizard;
}
/**
* @return void
*/
protected function configure() {
$this
->setName('notify_push:setup')
->setDescription('Configure push server')
->addArgument('server', InputArgument::OPTIONAL, "url of the push server");
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output) {
$server = $input->getArgument('server');
if ($server) {
$result = $this->test->test($server, $output);
if ($result === 0) {
$this->config->setAppValue('notify_push', 'base_endpoint', $server);
$output->writeln(" configuration saved");
}
return $result;
} else {
if (!$this->setupWizard->hasBundledBinaries()) {
$output->writeln("<error>🗴 bundled binaries are not available.</error>");
$output->writeln(" If you're trying to setup the app from git, you can find build instruction in the README: https://github.com/nextcloud/notify_push");
$output->writeln(" And pre-built binaries for x86_64, armv7, aarch64 and freebsd (amd64) in the github actions.");
$output->writeln(" Once you have a <info>notify_push</info> binary it should be placed in <info>" . realpath(__DIR__ . '/../../'). '/bin/' . $this->setupWizard->getArch()) . "</info>";
return 1;
}
$output->writeln("This setup wizard is intended for use on single server instances");
$output->writeln("where the nextcloud server, web server/reverse proxy and push daemon all run on the same machine.");
$output->writeln("If your setup is more complex or involves any kind of load balancing");
$output->writeln("you should follow the manual setup instruction on the README instead");
$output->writeln("<info>https://github.com/nextcloud/notify_push</info>");
if (!$this->enterToContinue($output)) {
return 0;
}
if (!$this->setupWizard->hasRedis()) {
$output->writeln("<error>🗴 redis is required.</error>");
return 1;
}
$url = $this->config->getSystemValueString('overwrite.cli.url', '');
if (!$url) {
$output->writeln("<error>🗴 'overwrite.cli.url' needs to be configured in your system config.</error>");
$output->writeln(" See https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/config_sample_php_parameters.html#proxy-configurations");
}
if (strpos($url, 'localhost') !== false) {
$output->writeln("<comment>🗴 'overwrite.cli.url' is set to localhost, the push server will not be reachable from other machines</comment>");
}
if (!$this->setupWizard->hasBinary()) {
$output->writeln("<error>🗴 your system architecture(" . $this->setupWizard->getArch() .") is not supported by the bundled binaries.</error>");
$output->writeln(" you can find build instructions for the notify_push binary in the README: https://github.com/nextcloud/notify_push");
$output->writeln(" And pre-built binaries for x86_64, armv7, aarch64 and freebsd (amd64) in the github actions.");
$output->writeln(" Once you have a <info>notify_push</info> binary it should be placed in <info>" . realpath(__DIR__ . '/../../bin/' . $this->setupWizard->getArch())) . "</info>";
return 1;
}
if (!$this->setupWizard->testBinary()) {
$output->writeln("<error>🗴 bundled binary not working on your system.</error>");
if ($this->setupWizard->hasSELinux()) {
$output->writeln(" It looks like your system has SELinux enabled which might be blocking execution of the binary.");
}
$this->readmeLink($output);
return 1;
}
if (!$this->setupWizard->hasSystemd()) {
$output->writeln("<error>🗴 your system doesn't seem to be using systemd.</error>");
$output->writeln(" You can still use the app without systemd by following the manual setup instructions.");
$this->readmeLink($output);
return 1;
}
$trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
if (array_search('127.0.0.1', $trustedProxies) === false) {
$trustedProxies[] = '127.0.0.1';
$this->config->setSystemValue('trusted_proxies', $trustedProxies);
}
if (array_search('::1', $trustedProxies) === false) {
$trustedProxies[] = '::1';
$this->config->setSystemValue('trusted_proxies', $trustedProxies);
}
if (!$this->setupWizard->isBinaryRunningAtDefaultPort()) {
if (!$this->setupWizard->isPortFree()) {
$output->writeln("<error>🗴 default port(7867) is in use.</error>");
$output->writeln(" if you've already setup the notify_push binary then call the setup command with the address it's listening on.");
$this->readmeLink($output);
return 1;
}
$selfSigned = $this->setupWizard->isSelfSigned();
if ($selfSigned) {
$output->writeln("<comment> Allowing self-signed certificates in the push config.</comment>");
}
$testResult = $this->setupWizard->testAutoConfig($selfSigned);
if ($testResult !== true) {
$output->writeln("<error>🗴 failed to run self-test with auto-generated config.</error>");
if (is_string($testResult)) {
$this->printTestResult($output, $testResult);
}
$this->readmeLink($output);
return 1;
}
$systemd = $this->setupWizard->generateSystemdService($selfSigned);
$output->writeln("Place the following systemd config at <info>/etc/systemd/system/notify_push.service</info>");
$output->writeln("");
$output->writeln($systemd);
$output->writeln("");
$output->writeln("And run <info>sudo systemctl enable --now notify_push</info>");
if (!$this->enterToContinue($output)) {
return 0;
}
if (!$this->setupWizard->isBinaryRunningAtDefaultPort()) {
$output->writeln("<error>🗴 push binary doesn't seem to be running, did you follow the above instructions?.</error>");
$this->readmeLink($output);
return 1;
}
} else {
$output->writeln("Push binary seems to be running already");
}
$testResult = $this->setupWizard->selfTestNonProxied();
if ($testResult !== true) {
$output->writeln("<error>🗴 failed to run self-test.</error>");
if (is_string($testResult)) {
$this->printTestResult($output, $testResult);
}
$this->readmeLink($output);
return 1;
}
$output->writeln("<info>✓ push server seems to be functioning correctly.</info>");
if (!$this->setupWizard->isBinaryRunningBehindProxy()) {
$proxy = $this->setupWizard->guessProxy();
if ($proxy === 'nginx') {
$output->writeln("Place the following nginx config within the <info>server</info> block of the nginx config for your nextcloud installation");
$output->writeln("which can usually be found within <info>/etc/nginx/sites-enabled/</info>");
$output->writeln("");
$output->writeln($this->setupWizard->nginxConfig());
$output->writeln("");
$output->writeln("And reload the config using <info>sudo nginx -s reload</info>");
} elseif ($proxy === 'apache') {
$output->writeln("Run the following commands to enable the proxy modules");
$output->writeln(" <info>sudo a2enmod proxy</info>");
$output->writeln(" <info>sudo a2enmod proxy_http</info>");
$output->writeln(" <info>sudo a2enmod proxy_wstunnel</info>");
$output->writeln("");
$output->writeln("Then place the following within the <info><VirtualHost></info> block of the apache config for your nextcloud installation");
$output->writeln("which can usually be found within <info>/etc/apache2/sites-enabled/</info>");
$output->writeln("Note that there might be both an <info>http</info> and <info>https</info> config file");
$output->writeln("");
$output->writeln($this->setupWizard->apacheConfig());
$output->writeln("");
$output->writeln("And reload apache using <info>sudo systemctl restart apache2</info>");
} else {
$output->writeln("<error>🗴 failed to detect reverse proxy.</error>");
$this->readmeLink($output);
return 1;
}
if (!$this->enterToContinue($output)) {
return 0;
}
if (!$this->setupWizard->isBinaryRunningBehindProxy()) {
$output->writeln("<error>🗴 push binary doesn't seem to be reachable trough the reverse proxy, did you follow the above instructions?.</error>");
$this->readmeLink($output);
return 1;
}
} else {
$output->writeln("Reverse proxy seems to be configured already");
}
$testResult = $this->setupWizard->selfTestProxied();
if ($testResult !== true) {
$output->writeln("<error>🗴 failed to run self-test.</error>");
if (is_string($testResult)) {
$this->printTestResult($output, $testResult);
}
$this->readmeLink($output);
return 1;
}
$output->writeln("<info>✓ reverse proxy seems to be setup correctly.</info>");
$this->config->setAppValue('notify_push', 'base_endpoint', $this->setupWizard->getProxiedBase());
$output->writeln(" configuration saved");
}
return 0;
}
private function readmeLink(OutputInterface $output): void {
$output->writeln(" See the steps in the README for manual setup instructions: https://github.com/nextcloud/notify_push");
}
private function printTestResult(OutputInterface $output, string $result): void {
$lines = explode("\n", $result);
foreach ($lines as $i => &$line) {
if ($i === 0) {
$line = 'test output: ' . $line;
} else {
$line = ' ' . $line;
}
$output->writeln($line);
}
}
private function enterToContinue(OutputInterface $output): bool {
$output->write("Press enter to continue or ESC to cancel...");
system('stty cbreak');
$result = null;
while ($result === null) {
$key = fgetc(STDIN);
if ($key === "\e") {
$result = false;
} elseif ($key === "\n") {
$result = true;
}
usleep(100);
}
system('stty -cbreak');
$output->writeln("");
return $result;
}
}