|
|
@@ -1,4 +1,7 @@ |
|
|
|
<?php |
|
|
|
|
|
|
|
declare(strict_types=1); |
|
|
|
|
|
|
|
/** |
|
|
|
* @copyright Copyright (c) 2016, ownCloud, Inc. |
|
|
|
* |
|
|
@@ -57,48 +60,37 @@ use OC\Log\Rotate; |
|
|
|
use OC\Preview\BackgroundCleanupJob; |
|
|
|
use OC\TextProcessing\RemoveOldTasksBackgroundJob; |
|
|
|
use OCP\AppFramework\Utility\ITimeFactory; |
|
|
|
use OCP\BackgroundJob\IJobList; |
|
|
|
use OCP\Defaults; |
|
|
|
use OCP\IConfig; |
|
|
|
use OCP\IGroup; |
|
|
|
use OCP\IGroupManager; |
|
|
|
use OCP\IL10N; |
|
|
|
use OCP\IRequest; |
|
|
|
use OCP\IUserManager; |
|
|
|
use OCP\IUserSession; |
|
|
|
use OCP\L10N\IFactory as IL10NFactory; |
|
|
|
use OCP\Migration\IOutput; |
|
|
|
use OCP\Security\ISecureRandom; |
|
|
|
use OCP\Server; |
|
|
|
use Psr\Log\LoggerInterface; |
|
|
|
|
|
|
|
class Setup { |
|
|
|
/** @var SystemConfig */ |
|
|
|
protected $config; |
|
|
|
/** @var IniGetWrapper */ |
|
|
|
protected $iniWrapper; |
|
|
|
/** @var IL10N */ |
|
|
|
protected $l10n; |
|
|
|
/** @var Defaults */ |
|
|
|
protected $defaults; |
|
|
|
/** @var LoggerInterface */ |
|
|
|
protected $logger; |
|
|
|
/** @var ISecureRandom */ |
|
|
|
protected $random; |
|
|
|
/** @var Installer */ |
|
|
|
protected $installer; |
|
|
|
protected IL10N $l10n; |
|
|
|
|
|
|
|
public function __construct( |
|
|
|
SystemConfig $config, |
|
|
|
IniGetWrapper $iniWrapper, |
|
|
|
IL10N $l10n, |
|
|
|
Defaults $defaults, |
|
|
|
LoggerInterface $logger, |
|
|
|
ISecureRandom $random, |
|
|
|
Installer $installer |
|
|
|
protected SystemConfig $config, |
|
|
|
protected IniGetWrapper $iniWrapper, |
|
|
|
IL10NFactory $l10nFactory, |
|
|
|
protected Defaults $defaults, |
|
|
|
protected LoggerInterface $logger, |
|
|
|
protected ISecureRandom $random, |
|
|
|
protected Installer $installer |
|
|
|
) { |
|
|
|
$this->config = $config; |
|
|
|
$this->iniWrapper = $iniWrapper; |
|
|
|
$this->l10n = $l10n; |
|
|
|
$this->defaults = $defaults; |
|
|
|
$this->logger = $logger; |
|
|
|
$this->random = $random; |
|
|
|
$this->installer = $installer; |
|
|
|
$this->l10n = $l10nFactory->get('lib'); |
|
|
|
} |
|
|
|
|
|
|
|
protected static $dbSetupClasses = [ |
|
|
|
protected static array $dbSetupClasses = [ |
|
|
|
'mysql' => \OC\Setup\MySQL::class, |
|
|
|
'pgsql' => \OC\Setup\PostgreSQL::class, |
|
|
|
'oci' => \OC\Setup\OCI::class, |
|
|
@@ -108,30 +100,22 @@ class Setup { |
|
|
|
|
|
|
|
/** |
|
|
|
* Wrapper around the "class_exists" PHP function to be able to mock it |
|
|
|
* |
|
|
|
* @param string $name |
|
|
|
* @return bool |
|
|
|
*/ |
|
|
|
protected function class_exists($name) { |
|
|
|
protected function class_exists(string $name): bool { |
|
|
|
return class_exists($name); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Wrapper around the "is_callable" PHP function to be able to mock it |
|
|
|
* |
|
|
|
* @param string $name |
|
|
|
* @return bool |
|
|
|
*/ |
|
|
|
protected function is_callable($name) { |
|
|
|
protected function is_callable(string $name): bool { |
|
|
|
return is_callable($name); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Wrapper around \PDO::getAvailableDrivers |
|
|
|
* |
|
|
|
* @return array |
|
|
|
*/ |
|
|
|
protected function getAvailableDbDriversForPdo() { |
|
|
|
protected function getAvailableDbDriversForPdo(): array { |
|
|
|
if (class_exists(\PDO::class)) { |
|
|
|
return \PDO::getAvailableDrivers(); |
|
|
|
} |
|
|
@@ -141,11 +125,10 @@ class Setup { |
|
|
|
/** |
|
|
|
* Get the available and supported databases of this instance |
|
|
|
* |
|
|
|
* @param bool $allowAllDatabases |
|
|
|
* @return array |
|
|
|
* @throws Exception |
|
|
|
*/ |
|
|
|
public function getSupportedDatabases($allowAllDatabases = false) { |
|
|
|
public function getSupportedDatabases(bool $allowAllDatabases = false): array { |
|
|
|
$availableDatabases = [ |
|
|
|
'sqlite' => [ |
|
|
|
'type' => 'pdo', |
|
|
@@ -207,7 +190,7 @@ class Setup { |
|
|
|
* @return array of system info, including an "errors" value |
|
|
|
* in case of errors/warnings |
|
|
|
*/ |
|
|
|
public function getSystemInfo($allowAllDatabases = false) { |
|
|
|
public function getSystemInfo(bool $allowAllDatabases = false): array { |
|
|
|
$databases = $this->getSupportedDatabases($allowAllDatabases); |
|
|
|
|
|
|
|
$dataDir = $this->config->getValue('datadirectory', \OC::$SERVERROOT . '/data'); |
|
|
@@ -227,7 +210,7 @@ class Setup { |
|
|
|
|
|
|
|
try { |
|
|
|
$util = new \OC_Util(); |
|
|
|
$htAccessWorking = $util->isHtaccessWorking(\OC::$server->getConfig()); |
|
|
|
$htAccessWorking = $util->isHtaccessWorking(Server::get(IConfig::class)); |
|
|
|
} catch (\OCP\HintException $e) { |
|
|
|
$errors[] = [ |
|
|
|
'error' => $e->getMessage(), |
|
|
@@ -273,10 +256,9 @@ class Setup { |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param $options |
|
|
|
* @return array |
|
|
|
* @return array<string|array> errors |
|
|
|
*/ |
|
|
|
public function install($options, ?IOutput $output = null) { |
|
|
|
public function install(array $options, ?IOutput $output = null): array { |
|
|
|
$l = $this->l10n; |
|
|
|
|
|
|
|
$error = []; |
|
|
@@ -314,7 +296,7 @@ class Setup { |
|
|
|
return $error; |
|
|
|
} |
|
|
|
|
|
|
|
$request = \OC::$server->getRequest(); |
|
|
|
$request = Server::get(IRequest::class); |
|
|
|
|
|
|
|
//no errors, good |
|
|
|
if (isset($options['trusted_domains']) |
|
|
@@ -387,78 +369,83 @@ class Setup { |
|
|
|
//create the user and group |
|
|
|
$user = null; |
|
|
|
try { |
|
|
|
$user = \OC::$server->getUserManager()->createUser($username, $password); |
|
|
|
$user = Server::get(IUserManager::class)->createUser($username, $password); |
|
|
|
if (!$user) { |
|
|
|
$error[] = "User <$username> could not be created."; |
|
|
|
return $error; |
|
|
|
} |
|
|
|
} catch (Exception $exception) { |
|
|
|
$error[] = $exception->getMessage(); |
|
|
|
return $error; |
|
|
|
} |
|
|
|
|
|
|
|
if (empty($error)) { |
|
|
|
$config = \OC::$server->getConfig(); |
|
|
|
$config->setAppValue('core', 'installedat', (string)microtime(true)); |
|
|
|
$config->setAppValue('core', 'lastupdatedat', (string)microtime(true)); |
|
|
|
$config = Server::get(IConfig::class); |
|
|
|
$config->setAppValue('core', 'installedat', (string)microtime(true)); |
|
|
|
$config->setAppValue('core', 'lastupdatedat', (string)microtime(true)); |
|
|
|
|
|
|
|
$vendorData = $this->getVendorData(); |
|
|
|
$config->setAppValue('core', 'vendor', $vendorData['vendor']); |
|
|
|
if ($vendorData['channel'] !== 'stable') { |
|
|
|
$config->setSystemValue('updater.release.channel', $vendorData['channel']); |
|
|
|
} |
|
|
|
$vendorData = $this->getVendorData(); |
|
|
|
$config->setAppValue('core', 'vendor', $vendorData['vendor']); |
|
|
|
if ($vendorData['channel'] !== 'stable') { |
|
|
|
$config->setSystemValue('updater.release.channel', $vendorData['channel']); |
|
|
|
} |
|
|
|
|
|
|
|
$group = \OC::$server->getGroupManager()->createGroup('admin'); |
|
|
|
if ($group instanceof IGroup) { |
|
|
|
$group->addUser($user); |
|
|
|
} |
|
|
|
$group = Server::get(IGroupManager::class)->createGroup('admin'); |
|
|
|
if ($group instanceof IGroup) { |
|
|
|
$group->addUser($user); |
|
|
|
} |
|
|
|
|
|
|
|
// Install shipped apps and specified app bundles |
|
|
|
$this->outputDebug($output, 'Install default apps'); |
|
|
|
Installer::installShippedApps(false, $output); |
|
|
|
// Install shipped apps and specified app bundles |
|
|
|
$this->outputDebug($output, 'Install default apps'); |
|
|
|
Installer::installShippedApps(false, $output); |
|
|
|
|
|
|
|
// create empty file in data dir, so we can later find |
|
|
|
// out that this is indeed an ownCloud data directory |
|
|
|
$this->outputDebug($output, 'Setup data directory'); |
|
|
|
file_put_contents($config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); |
|
|
|
// create empty file in data dir, so we can later find |
|
|
|
// out that this is indeed an ownCloud data directory |
|
|
|
$this->outputDebug($output, 'Setup data directory'); |
|
|
|
file_put_contents($config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); |
|
|
|
|
|
|
|
// Update .htaccess files |
|
|
|
self::updateHtaccess(); |
|
|
|
self::protectDataDirectory(); |
|
|
|
// Update .htaccess files |
|
|
|
self::updateHtaccess(); |
|
|
|
self::protectDataDirectory(); |
|
|
|
|
|
|
|
$this->outputDebug($output, 'Install background jobs'); |
|
|
|
self::installBackgroundJobs(); |
|
|
|
$this->outputDebug($output, 'Install background jobs'); |
|
|
|
self::installBackgroundJobs(); |
|
|
|
|
|
|
|
//and we are done |
|
|
|
$config->setSystemValue('installed', true); |
|
|
|
if (self::shouldRemoveCanInstallFile()) { |
|
|
|
unlink(\OC::$configDir.'/CAN_INSTALL'); |
|
|
|
} |
|
|
|
|
|
|
|
$bootstrapCoordinator = \OCP\Server::get(\OC\AppFramework\Bootstrap\Coordinator::class); |
|
|
|
$bootstrapCoordinator->runInitialRegistration(); |
|
|
|
//and we are done |
|
|
|
$config->setSystemValue('installed', true); |
|
|
|
if (self::shouldRemoveCanInstallFile()) { |
|
|
|
unlink(\OC::$configDir.'/CAN_INSTALL'); |
|
|
|
} |
|
|
|
|
|
|
|
// Create a session token for the newly created user |
|
|
|
// The token provider requires a working db, so it's not injected on setup |
|
|
|
/* @var $userSession User\Session */ |
|
|
|
$userSession = \OC::$server->getUserSession(); |
|
|
|
$provider = \OCP\Server::get(PublicKeyTokenProvider::class); |
|
|
|
$userSession->setTokenProvider($provider); |
|
|
|
$userSession->login($username, $password); |
|
|
|
$userSession->createSessionToken($request, $userSession->getUser()->getUID(), $username, $password); |
|
|
|
$bootstrapCoordinator = \OCP\Server::get(\OC\AppFramework\Bootstrap\Coordinator::class); |
|
|
|
$bootstrapCoordinator->runInitialRegistration(); |
|
|
|
|
|
|
|
// Create a session token for the newly created user |
|
|
|
// The token provider requires a working db, so it's not injected on setup |
|
|
|
/** @var \OC\User\Session $userSession */ |
|
|
|
$userSession = Server::get(IUserSession::class); |
|
|
|
$provider = Server::get(PublicKeyTokenProvider::class); |
|
|
|
$userSession->setTokenProvider($provider); |
|
|
|
$userSession->login($username, $password); |
|
|
|
$user = $userSession->getUser(); |
|
|
|
if (!$user) { |
|
|
|
$error[] = "No user found in session."; |
|
|
|
return $error; |
|
|
|
} |
|
|
|
$userSession->createSessionToken($request, $user->getUID(), $username, $password); |
|
|
|
|
|
|
|
$session = $userSession->getSession(); |
|
|
|
$session->set('last-password-confirm', \OCP\Server::get(ITimeFactory::class)->getTime()); |
|
|
|
$session = $userSession->getSession(); |
|
|
|
$session->set('last-password-confirm', Server::get(ITimeFactory::class)->getTime()); |
|
|
|
|
|
|
|
// Set email for admin |
|
|
|
if (!empty($options['adminemail'])) { |
|
|
|
$user->setSystemEMailAddress($options['adminemail']); |
|
|
|
} |
|
|
|
// Set email for admin |
|
|
|
if (!empty($options['adminemail'])) { |
|
|
|
$user->setSystemEMailAddress($options['adminemail']); |
|
|
|
} |
|
|
|
|
|
|
|
return $error; |
|
|
|
} |
|
|
|
|
|
|
|
public static function installBackgroundJobs() { |
|
|
|
$jobList = \OC::$server->getJobList(); |
|
|
|
public static function installBackgroundJobs(): void { |
|
|
|
$jobList = Server::get(IJobList::class); |
|
|
|
$jobList->add(TokenCleanupJob::class); |
|
|
|
$jobList->add(Rotate::class); |
|
|
|
$jobList->add(BackgroundCleanupJob::class); |
|
|
@@ -468,15 +455,13 @@ class Setup { |
|
|
|
/** |
|
|
|
* @return string Absolute path to htaccess |
|
|
|
*/ |
|
|
|
private function pathToHtaccess() { |
|
|
|
private function pathToHtaccess(): string { |
|
|
|
return \OC::$SERVERROOT . '/.htaccess'; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Find webroot from config |
|
|
|
* |
|
|
|
* @param SystemConfig $config |
|
|
|
* @return string |
|
|
|
* @throws InvalidArgumentException when invalid value for overwrite.cli.url |
|
|
|
*/ |
|
|
|
private static function findWebRoot(SystemConfig $config): string { |
|
|
@@ -503,8 +488,8 @@ class Setup { |
|
|
|
* @return bool True when success, False otherwise |
|
|
|
* @throws \OCP\AppFramework\QueryException |
|
|
|
*/ |
|
|
|
public static function updateHtaccess() { |
|
|
|
$config = \OC::$server->getSystemConfig(); |
|
|
|
public static function updateHtaccess(): bool { |
|
|
|
$config = Server::get(SystemConfig::class); |
|
|
|
|
|
|
|
try { |
|
|
|
$webRoot = self::findWebRoot($config); |
|
|
@@ -512,15 +497,7 @@ class Setup { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
$setupHelper = new \OC\Setup( |
|
|
|
$config, |
|
|
|
\OC::$server->get(IniGetWrapper::class), |
|
|
|
\OC::$server->getL10N('lib'), |
|
|
|
\OCP\Server::get(Defaults::class), |
|
|
|
\OC::$server->get(LoggerInterface::class), |
|
|
|
\OC::$server->getSecureRandom(), |
|
|
|
\OCP\Server::get(Installer::class) |
|
|
|
); |
|
|
|
$setupHelper = Server::get(\OC\Setup::class); |
|
|
|
|
|
|
|
if (!is_writable($setupHelper->pathToHtaccess())) { |
|
|
|
return false; |
|
|
@@ -563,23 +540,19 @@ class Setup { |
|
|
|
$content .= "\n</IfModule>"; |
|
|
|
} |
|
|
|
|
|
|
|
if ($content !== '') { |
|
|
|
// Never write file back if disk space should be too low |
|
|
|
if (function_exists('disk_free_space')) { |
|
|
|
$df = disk_free_space(\OC::$SERVERROOT); |
|
|
|
$size = strlen($content) + 10240; |
|
|
|
if ($df !== false && $df < (float)$size) { |
|
|
|
throw new \Exception(\OC::$SERVERROOT . " does not have enough space for writing the htaccess file! Not writing it back!"); |
|
|
|
} |
|
|
|
// Never write file back if disk space should be too low |
|
|
|
if (function_exists('disk_free_space')) { |
|
|
|
$df = disk_free_space(\OC::$SERVERROOT); |
|
|
|
$size = strlen($content) + 10240; |
|
|
|
if ($df !== false && $df < (float)$size) { |
|
|
|
throw new \Exception(\OC::$SERVERROOT . " does not have enough space for writing the htaccess file! Not writing it back!"); |
|
|
|
} |
|
|
|
//suppress errors in case we don't have permissions for it |
|
|
|
return (bool)@file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent . $content . "\n"); |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
//suppress errors in case we don't have permissions for it |
|
|
|
return (bool)@file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent . $content . "\n"); |
|
|
|
} |
|
|
|
|
|
|
|
public static function protectDataDirectory() { |
|
|
|
public static function protectDataDirectory(): void { |
|
|
|
//Require all denied |
|
|
|
$now = date('Y-m-d H:i:s'); |
|
|
|
$content = "# Generated by Nextcloud on $now\n"; |
|
|
@@ -607,7 +580,7 @@ class Setup { |
|
|
|
$content .= " IndexIgnore *\n"; |
|
|
|
$content .= "</IfModule>"; |
|
|
|
|
|
|
|
$baseDir = \OC::$server->getConfig()->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data'); |
|
|
|
$baseDir = Server::get(IConfig::class)->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data'); |
|
|
|
file_put_contents($baseDir . '/.htaccess', $content); |
|
|
|
file_put_contents($baseDir . '/index.html', ''); |
|
|
|
} |
|
|
@@ -623,17 +596,11 @@ class Setup { |
|
|
|
]; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @return bool |
|
|
|
*/ |
|
|
|
public function shouldRemoveCanInstallFile() { |
|
|
|
public function shouldRemoveCanInstallFile(): bool { |
|
|
|
return \OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL'); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @return bool |
|
|
|
*/ |
|
|
|
public function canInstallFileExists() { |
|
|
|
public function canInstallFileExists(): bool { |
|
|
|
return is_file(\OC::$configDir.'/CAN_INSTALL'); |
|
|
|
} |
|
|
|
|