Make supported DBs configurable within config.phptags/v8.0.0alpha1
), | ), | ||||
), | ), | ||||
/** | |||||
* Database types that are supported for installation | |||||
* Available: | |||||
* - sqlite (SQLite3) | |||||
* - mysql (MySQL) | |||||
* - pgsql (PostgreSQL) | |||||
* - oci (Oracle) | |||||
* - mssql (Microsoft SQL Server) | |||||
*/ | |||||
'supportedDatabases' => array( | |||||
'sqlite', | |||||
'mysql', | |||||
'pgsql', | |||||
'oci', | |||||
'mssql' | |||||
), | |||||
/** | /** | ||||
* Custom CSP policy, changing this will overwrite the standard policy | * Custom CSP policy, changing this will overwrite the standard policy | ||||
*/ | */ |
<?php | <?php | ||||
/** | /** | ||||
* Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl> | * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl> | ||||
* Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> | |||||
* This file is licensed under the Affero General Public License version 3 or | * This file is licensed under the Affero General Public License version 3 or | ||||
* later. | * later. | ||||
* See the COPYING-README file. | * See the COPYING-README file. | ||||
namespace OC\Core\Setup; | namespace OC\Core\Setup; | ||||
use OCP\IConfig; | |||||
class Controller { | class Controller { | ||||
/** @var \OCP\IConfig */ | |||||
protected $config; | |||||
/** | |||||
* @param IConfig $config | |||||
*/ | |||||
function __construct(IConfig $config) { | |||||
$this->config = $config; | |||||
} | |||||
public function run($post) { | public function run($post) { | ||||
// Check for autosetup: | // Check for autosetup: | ||||
$post = $this->loadAutoConfig($post); | $post = $this->loadAutoConfig($post); | ||||
* in case of errors/warnings | * in case of errors/warnings | ||||
*/ | */ | ||||
public function getSystemInfo() { | public function getSystemInfo() { | ||||
$hasSQLite = class_exists('SQLite3'); | |||||
$hasMySQL = is_callable('mysql_connect'); | |||||
$hasPostgreSQL = is_callable('pg_connect'); | |||||
$hasOracle = is_callable('oci_connect'); | |||||
$hasMSSQL = is_callable('sqlsrv_connect'); | |||||
$databases = array(); | |||||
if ($hasSQLite) { | |||||
$databases['sqlite'] = 'SQLite'; | |||||
} | |||||
if ($hasMySQL) { | |||||
$databases['mysql'] = 'MySQL/MariaDB'; | |||||
} | |||||
if ($hasPostgreSQL) { | |||||
$databases['pgsql'] = 'PostgreSQL'; | |||||
} | |||||
if ($hasOracle) { | |||||
$databases['oci'] = 'Oracle'; | |||||
} | |||||
if ($hasMSSQL) { | |||||
$databases['mssql'] = 'MS SQL'; | |||||
} | |||||
$datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); | |||||
$setup = new \OC_Setup($this->config); | |||||
$databases = $setup->getSupportedDatabases(); | |||||
$dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data'); | |||||
$vulnerableToNullByte = false; | $vulnerableToNullByte = false; | ||||
if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243) | if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243) | ||||
$vulnerableToNullByte = true; | $vulnerableToNullByte = true; | ||||
// Create data directory to test whether the .htaccess works | // Create data directory to test whether the .htaccess works | ||||
// Notice that this is not necessarily the same data directory as the one | // Notice that this is not necessarily the same data directory as the one | ||||
// that will effectively be used. | // that will effectively be used. | ||||
@mkdir($datadir); | |||||
if (is_dir($datadir) && is_writable($datadir)) { | |||||
@mkdir($dataDir); | |||||
$htAccessWorking = true; | |||||
if (is_dir($dataDir) && is_writable($dataDir)) { | |||||
// Protect data directory here, so we can test if the protection is working | // Protect data directory here, so we can test if the protection is working | ||||
\OC_Setup::protectDataDirectory(); | \OC_Setup::protectDataDirectory(); | ||||
try { | try { | ||||
$htaccessWorking = \OC_Util::isHtaccessWorking(); | |||||
$htAccessWorking = \OC_Util::isHtaccessWorking(); | |||||
} catch (\OC\HintException $e) { | } catch (\OC\HintException $e) { | ||||
$errors[] = array( | $errors[] = array( | ||||
'error' => $e->getMessage(), | 'error' => $e->getMessage(), | ||||
'hint' => $e->getHint() | 'hint' => $e->getHint() | ||||
); | ); | ||||
$htaccessWorking = false; | |||||
$htAccessWorking = false; | |||||
} | } | ||||
} | } | ||||
if (\OC_Util::runningOnMac()) { | if (\OC_Util::runningOnMac()) { | ||||
$l10n = \OC::$server->getL10N('core'); | $l10n = \OC::$server->getL10N('core'); | ||||
$themeName = \OC_Util::getTheme(); | |||||
$theme = new \OC_Defaults(); | $theme = new \OC_Defaults(); | ||||
$errors[] = array( | $errors[] = array( | ||||
'error' => $l10n->t( | 'error' => $l10n->t( | ||||
} | } | ||||
return array( | return array( | ||||
'hasSQLite' => $hasSQLite, | |||||
'hasMySQL' => $hasMySQL, | |||||
'hasPostgreSQL' => $hasPostgreSQL, | |||||
'hasOracle' => $hasOracle, | |||||
'hasMSSQL' => $hasMSSQL, | |||||
'hasSQLite' => isset($databases['sqlite']), | |||||
'hasMySQL' => isset($databases['mysql']), | |||||
'hasPostgreSQL' => isset($databases['postgre']), | |||||
'hasOracle' => isset($databases['oci']), | |||||
'hasMSSQL' => isset($databases['mssql']), | |||||
'databases' => $databases, | 'databases' => $databases, | ||||
'directory' => $datadir, | |||||
'htaccessWorking' => $htaccessWorking, | |||||
'directory' => $dataDir, | |||||
'htaccessWorking' => $htAccessWorking, | |||||
'vulnerableToNullByte' => $vulnerableToNullByte, | 'vulnerableToNullByte' => $vulnerableToNullByte, | ||||
'errors' => $errors, | 'errors' => $errors, | ||||
); | ); |
// Check if ownCloud is installed or in maintenance (update) mode | // Check if ownCloud is installed or in maintenance (update) mode | ||||
if (!OC_Config::getValue('installed', false)) { | if (!OC_Config::getValue('installed', false)) { | ||||
$controller = new OC\Core\Setup\Controller(); | |||||
$controller = new OC\Core\Setup\Controller(\OC::$server->getConfig()); | |||||
$controller->run($_POST); | $controller->run($_POST); | ||||
exit(); | exit(); | ||||
} | } |
<?php | <?php | ||||
/** | |||||
* Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> | |||||
* This file is licensed under the Affero General Public License version 3 or | |||||
* later. | |||||
* See the COPYING-README file. | |||||
*/ | |||||
use OCP\IConfig; | |||||
class DatabaseSetupException extends \OC\HintException { | class DatabaseSetupException extends \OC\HintException { | ||||
} | } | ||||
class OC_Setup { | class OC_Setup { | ||||
/** @var IConfig */ | |||||
protected $config; | |||||
/** | |||||
* @param IConfig $config | |||||
*/ | |||||
function __construct(IConfig $config) { | |||||
$this->config = $config; | |||||
} | |||||
static $dbSetupClasses = array( | static $dbSetupClasses = array( | ||||
'mysql' => '\OC\Setup\MySQL', | 'mysql' => '\OC\Setup\MySQL', | ||||
'pgsql' => '\OC\Setup\PostgreSQL', | 'pgsql' => '\OC\Setup\PostgreSQL', | ||||
'sqlite3' => '\OC\Setup\Sqlite', | 'sqlite3' => '\OC\Setup\Sqlite', | ||||
); | ); | ||||
/** | |||||
* @return OC_L10N | |||||
*/ | |||||
public static function getTrans(){ | public static function getTrans(){ | ||||
return \OC::$server->getL10N('lib'); | return \OC::$server->getL10N('lib'); | ||||
} | } | ||||
/** | |||||
* Wrapper around the "class_exists" PHP function to be able to mock it | |||||
* @param string $name | |||||
* @return bool | |||||
*/ | |||||
public function class_exists($name) { | |||||
return class_exists($name); | |||||
} | |||||
/** | |||||
* Wrapper around the "is_callable" PHP function to be able to mock it | |||||
* @param string $name | |||||
* @return bool | |||||
*/ | |||||
public function is_callable($name) { | |||||
return is_callable($name); | |||||
} | |||||
/** | |||||
* Get the available and supported databases of this instance | |||||
* | |||||
* @throws Exception | |||||
* @return array | |||||
*/ | |||||
public function getSupportedDatabases() { | |||||
$availableDatabases = array( | |||||
'sqlite' => array( | |||||
'type' => 'class', | |||||
'call' => 'SQLite3', | |||||
'name' => 'SQLite' | |||||
), | |||||
'mysql' => array( | |||||
'type' => 'function', | |||||
'call' => 'mysql_connect', | |||||
'name' => 'MySQL/MariaDB' | |||||
), | |||||
'pgsql' => array( | |||||
'type' => 'function', | |||||
'call' => 'oci_connect', | |||||
'name' => 'PostgreSQL' | |||||
), | |||||
'oci' => array( | |||||
'type' => 'function', | |||||
'call' => 'oci_connect', | |||||
'name' => 'Oracle' | |||||
), | |||||
'mssql' => array( | |||||
'type' => 'function', | |||||
'call' => 'sqlsrv_connect', | |||||
'name' => 'MS SQL' | |||||
) | |||||
); | |||||
$configuredDatabases = $this->config->getSystemValue('supportedDatabases', | |||||
array('sqlite', 'mysql', 'pgsql', 'oci', 'mssql')); | |||||
if(!is_array($configuredDatabases)) { | |||||
throw new Exception('Supported databases are not properly configured.'); | |||||
} | |||||
$supportedDatabases = array(); | |||||
foreach($configuredDatabases as $database) { | |||||
if(array_key_exists($database, $availableDatabases)) { | |||||
$working = false; | |||||
if($availableDatabases[$database]['type'] === 'class') { | |||||
$working = $this->class_exists($availableDatabases[$database]['call']); | |||||
} elseif ($availableDatabases[$database]['type'] === 'function') { | |||||
$working = $this->is_callable($availableDatabases[$database]['call']); | |||||
} | |||||
if($working) { | |||||
$supportedDatabases[$database] = $availableDatabases[$database]['name']; | |||||
} | |||||
} | |||||
} | |||||
return $supportedDatabases; | |||||
} | |||||
/** | |||||
* @param $options | |||||
* @return array | |||||
*/ | |||||
public static function install($options) { | public static function install($options) { | ||||
$l = self::getTrans(); | $l = self::getTrans(); | ||||
$error = array(); | $error = array(); | ||||
$dbtype = $options['dbtype']; | |||||
$dbType = $options['dbtype']; | |||||
if(empty($options['adminlogin'])) { | if(empty($options['adminlogin'])) { | ||||
$error[] = $l->t('Set an admin username.'); | $error[] = $l->t('Set an admin username.'); | ||||
$options['directory'] = OC::$SERVERROOT."/data"; | $options['directory'] = OC::$SERVERROOT."/data"; | ||||
} | } | ||||
if (!isset(self::$dbSetupClasses[$dbtype])) { | |||||
$dbtype = 'sqlite'; | |||||
if (!isset(self::$dbSetupClasses[$dbType])) { | |||||
$dbType = 'sqlite'; | |||||
} | } | ||||
$username = htmlspecialchars_decode($options['adminlogin']); | $username = htmlspecialchars_decode($options['adminlogin']); | ||||
$password = htmlspecialchars_decode($options['adminpass']); | $password = htmlspecialchars_decode($options['adminpass']); | ||||
$datadir = htmlspecialchars_decode($options['directory']); | |||||
$dataDir = htmlspecialchars_decode($options['directory']); | |||||
$class = self::$dbSetupClasses[$dbtype]; | |||||
$class = self::$dbSetupClasses[$dbType]; | |||||
/** @var \OC\Setup\AbstractDatabase $dbSetup */ | /** @var \OC\Setup\AbstractDatabase $dbSetup */ | ||||
$dbSetup = new $class(self::getTrans(), 'db_structure.xml'); | $dbSetup = new $class(self::getTrans(), 'db_structure.xml'); | ||||
$error = array_merge($error, $dbSetup->validate($options)); | $error = array_merge($error, $dbSetup->validate($options)); | ||||
// validate the data directory | // validate the data directory | ||||
if ( | if ( | ||||
(!is_dir($datadir) and !mkdir($datadir)) or | |||||
!is_writable($datadir) | |||||
(!is_dir($dataDir) and !mkdir($dataDir)) or | |||||
!is_writable($dataDir) | |||||
) { | ) { | ||||
$error[] = $l->t("Can't create or write into the data directory %s", array($datadir)); | |||||
$error[] = $l->t("Can't create or write into the data directory %s", array($dataDir)); | |||||
} | } | ||||
if(count($error) != 0) { | if(count($error) != 0) { | ||||
} | } | ||||
//no errors, good | //no errors, good | ||||
if( isset($options['trusted_domains']) | |||||
if(isset($options['trusted_domains']) | |||||
&& is_array($options['trusted_domains'])) { | && is_array($options['trusted_domains'])) { | ||||
$trustedDomains = $options['trusted_domains']; | $trustedDomains = $options['trusted_domains']; | ||||
} else { | } else { | ||||
} | } | ||||
if (OC_Util::runningOnWindows()) { | if (OC_Util::runningOnWindows()) { | ||||
$datadir = rtrim(realpath($datadir), '\\'); | |||||
$dataDir = rtrim(realpath($dataDir), '\\'); | |||||
} | } | ||||
//use sqlite3 when available, otherise sqlite2 will be used. | |||||
if($dbtype=='sqlite' and class_exists('SQLite3')) { | |||||
$dbtype='sqlite3'; | |||||
//use sqlite3 when available, otherwise sqlite2 will be used. | |||||
if($dbType=='sqlite' and class_exists('SQLite3')) { | |||||
$dbType='sqlite3'; | |||||
} | } | ||||
//generate a random salt that is used to salt the local user passwords | //generate a random salt that is used to salt the local user passwords | ||||
//write the config file | //write the config file | ||||
\OC::$server->getConfig()->setSystemValue('trusted_domains', $trustedDomains); | \OC::$server->getConfig()->setSystemValue('trusted_domains', $trustedDomains); | ||||
\OC::$server->getConfig()->setSystemValue('datadirectory', $datadir); | |||||
\OC::$server->getConfig()->setSystemValue('datadirectory', $dataDir); | |||||
\OC::$server->getConfig()->setSystemValue('overwrite.cli.url', \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost() . OC::$WEBROOT); | \OC::$server->getConfig()->setSystemValue('overwrite.cli.url', \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost() . OC::$WEBROOT); | ||||
\OC::$server->getConfig()->setSystemValue('dbtype', $dbtype); | |||||
\OC::$server->getConfig()->setSystemValue('dbtype', $dbType); | |||||
\OC::$server->getConfig()->setSystemValue('version', implode('.', OC_Util::getVersion())); | \OC::$server->getConfig()->setSystemValue('version', implode('.', OC_Util::getVersion())); | ||||
try { | try { | ||||
//create the user and group | //create the user and group | ||||
try { | try { | ||||
OC_User::createUser($username, $password); | OC_User::createUser($username, $password); | ||||
} | |||||
catch(Exception $exception) { | |||||
} catch(Exception $exception) { | |||||
$error[] = $exception->getMessage(); | $error[] = $exception->getMessage(); | ||||
} | } | ||||
} | } | ||||
$webServerRestart = false; | $webServerRestart = false; | ||||
//check for database drivers | |||||
if (!(is_callable('sqlite_open') or class_exists('SQLite3')) | |||||
and !is_callable('mysql_connect') | |||||
and !is_callable('pg_connect') | |||||
and !is_callable('oci_connect') | |||||
) { | |||||
$setup = new OC_Setup($config); | |||||
$availableDatabases = $setup->getSupportedDatabases(); | |||||
if (empty($availableDatabases)) { | |||||
$errors[] = array( | $errors[] = array( | ||||
'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'), | 'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'), | ||||
'hint' => '' //TODO: sane hint | 'hint' => '' //TODO: sane hint |
<?php | |||||
/** | |||||
* Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com> | |||||
* This file is licensed under the Affero General Public License version 3 or | |||||
* later. | |||||
* See the COPYING-README file. | |||||
*/ | |||||
use OCP\IConfig; | |||||
class Test_OC_Setup extends PHPUnit_Framework_TestCase { | |||||
/** @var IConfig */ | |||||
protected $config; | |||||
/** @var \OC_Setup */ | |||||
protected $setupClass; | |||||
public function setUp() { | |||||
$this->config = $this->getMock('\OCP\IConfig'); | |||||
$this->setupClass = $this->getMock('\OC_Setup', array('class_exists', 'is_callable'), array($this->config)); | |||||
} | |||||
public function testGetSupportedDatabasesWithOneWorking() { | |||||
$this->config | |||||
->expects($this->once()) | |||||
->method('getSystemValue') | |||||
->will($this->returnValue( | |||||
array('sqlite', 'mysql', 'oci') | |||||
)); | |||||
$this->setupClass | |||||
->expects($this->once()) | |||||
->method('class_exists') | |||||
->will($this->returnValue(true)); | |||||
$this->setupClass | |||||
->expects($this->exactly(2)) | |||||
->method('is_callable') | |||||
->will($this->returnValue(false)); | |||||
$result = $this->setupClass->getSupportedDatabases(); | |||||
$expectedResult = array( | |||||
'sqlite' => 'SQLite' | |||||
); | |||||
$this->assertSame($expectedResult, $result); | |||||
} | |||||
public function testGetSupportedDatabasesWithNoWorking() { | |||||
$this->config | |||||
->expects($this->once()) | |||||
->method('getSystemValue') | |||||
->will($this->returnValue( | |||||
array('sqlite', 'mysql', 'oci', 'pgsql') | |||||
)); | |||||
$this->setupClass | |||||
->expects($this->once()) | |||||
->method('class_exists') | |||||
->will($this->returnValue(false)); | |||||
$this->setupClass | |||||
->expects($this->exactly(3)) | |||||
->method('is_callable') | |||||
->will($this->returnValue(false)); | |||||
$result = $this->setupClass->getSupportedDatabases(); | |||||
$this->assertSame(array(), $result); | |||||
} | |||||
public function testGetSupportedDatabasesWitAllWorking() { | |||||
$this->config | |||||
->expects($this->once()) | |||||
->method('getSystemValue') | |||||
->will($this->returnValue( | |||||
array('sqlite', 'mysql', 'pgsql', 'oci', 'mssql') | |||||
)); | |||||
$this->setupClass | |||||
->expects($this->once()) | |||||
->method('class_exists') | |||||
->will($this->returnValue(true)); | |||||
$this->setupClass | |||||
->expects($this->exactly(4)) | |||||
->method('is_callable') | |||||
->will($this->returnValue(true)); | |||||
$result = $this->setupClass->getSupportedDatabases(); | |||||
$expectedResult = array( | |||||
'sqlite' => 'SQLite', | |||||
'mysql' => 'MySQL/MariaDB', | |||||
'pgsql' => 'PostgreSQL', | |||||
'oci' => 'Oracle', | |||||
'mssql' => 'MS SQL' | |||||
); | |||||
$this->assertSame($expectedResult, $result); | |||||
} | |||||
/** | |||||
* @expectedException \Exception | |||||
* @expectedExceptionMessage Supported databases are not properly configured. | |||||
*/ | |||||
public function testGetSupportedDatabaseException() { | |||||
$this->config | |||||
->expects($this->once()) | |||||
->method('getSystemValue') | |||||
->will($this->returnValue('NotAnArray')); | |||||
$this->setupClass->getSupportedDatabases(); | |||||
} | |||||
} |