|
|
|
|
@ -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');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|