Completed
Push — stable8 ( 420dab...a42074 )
by
unknown
10:01
created

OC_Setup::install()   F

Complexity

Conditions 20
Paths 2592

Size

Total Lines 126
Code Lines 74

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 74
nc 2592
nop 1
dl 0
loc 126
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright (c) 2014 Lukas Reschke <[email protected]>
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later.
6
 * See the COPYING-README file.
7
 */
8
9
use OCP\IConfig;
10
11
class OC_Setup {
12
	/** @var IConfig */
13
	protected $config;
14
15
	/**
16
	 * @param IConfig $config
17
	 */
18
	function __construct(IConfig $config) {
19
		$this->config = $config;
20
	}
21
22
	static $dbSetupClasses = array(
23
		'mysql' => '\OC\Setup\MySQL',
24
		'pgsql' => '\OC\Setup\PostgreSQL',
25
		'oci'   => '\OC\Setup\OCI',
26
		'mssql' => '\OC\Setup\MSSQL',
27
		'sqlite' => '\OC\Setup\Sqlite',
28
		'sqlite3' => '\OC\Setup\Sqlite',
29
	);
30
31
	/**
32
	 * @return OC_L10N
33
	 */
34
	public static function getTrans(){
35
		return \OC::$server->getL10N('lib');
36
	}
37
38
	/**
39
	 * Wrapper around the "class_exists" PHP function to be able to mock it
40
	 * @param string $name
41
	 * @return bool
42
	 */
43
	public function class_exists($name) {
44
		return class_exists($name);
45
	}
46
47
	/**
48
	 * Wrapper around the "is_callable" PHP function to be able to mock it
49
	 * @param string $name
50
	 * @return bool
51
	 */
52
	public function is_callable($name) {
53
		return is_callable($name);
54
	}
55
56
	/**
57
	 * Get the available and supported databases of this instance
58
	 *
59
	 * @throws Exception
60
	 * @return array
61
	 */
62
	public function getSupportedDatabases() {
63
		$availableDatabases = array(
64
			'sqlite' =>  array(
65
				'type' => 'class',
66
				'call' => 'SQLite3',
67
				'name' => 'SQLite'
68
			),
69
			'mysql' => array(
70
				'type' => 'function',
71
				'call' => 'mysql_connect',
72
				'name' => 'MySQL/MariaDB'
73
			),
74
			'pgsql' => array(
75
				'type' => 'function',
76
				'call' => 'pg_connect',
77
				'name' => 'PostgreSQL'
78
			),
79
			'oci' => array(
80
				'type' => 'function',
81
				'call' => 'oci_connect',
82
				'name' => 'Oracle'
83
			),
84
			'mssql' => array(
85
				'type' => 'function',
86
				'call' => 'sqlsrv_connect',
87
				'name' => 'MS SQL'
88
			)
89
		);
90
		$configuredDatabases = $this->config->getSystemValue('supportedDatabases',
91
			array('sqlite', 'mysql', 'pgsql'));
92
		if(!is_array($configuredDatabases)) {
93
			throw new Exception('Supported databases are not properly configured.');
94
		}
95
96
		$supportedDatabases = array();
97
98
		foreach($configuredDatabases as $database) {
99
			if(array_key_exists($database, $availableDatabases)) {
100
				$working = false;
101
				if($availableDatabases[$database]['type'] === 'class') {
102
					$working = $this->class_exists($availableDatabases[$database]['call']);
103
				} elseif ($availableDatabases[$database]['type'] === 'function') {
104
					$working = $this->is_callable($availableDatabases[$database]['call']);
105
				}
106
				if($working) {
107
					$supportedDatabases[$database] = $availableDatabases[$database]['name'];
108
				}
109
			}
110
		}
111
112
		return $supportedDatabases;
113
	}
114
115
	/**
116
	 * @param $options
117
	 * @return array
118
	 */
119
	public static function install($options) {
120
		$l = self::getTrans();
121
122
		$error = array();
123
		$dbType = $options['dbtype'];
124
125
		if(empty($options['adminlogin'])) {
126
			$error[] = $l->t('Set an admin username.');
127
		}
128
		if(empty($options['adminpass'])) {
129
			$error[] = $l->t('Set an admin password.');
130
		}
131
		if(empty($options['directory'])) {
132
			$options['directory'] = OC::$SERVERROOT."/data";
133
		}
134
135
		if (!isset(self::$dbSetupClasses[$dbType])) {
136
			$dbType = 'sqlite';
137
		}
138
139
		$username = htmlspecialchars_decode($options['adminlogin']);
140
		$password = htmlspecialchars_decode($options['adminpass']);
141
		$dataDir = htmlspecialchars_decode($options['directory']);
142
143
		$class = self::$dbSetupClasses[$dbType];
144
		/** @var \OC\Setup\AbstractDatabase $dbSetup */
145
		$dbSetup = new $class(self::getTrans(), 'db_structure.xml');
146
		$error = array_merge($error, $dbSetup->validate($options));
147
148
		// validate the data directory
149
		if (
150
			(!is_dir($dataDir) and !mkdir($dataDir)) or
151
			!is_writable($dataDir)
152
		) {
153
			$error[] = $l->t("Can't create or write into the data directory %s", array($dataDir));
154
		}
155
156
		if(count($error) != 0) {
157
			return $error;
158
		}
159
160
		//no errors, good
161
		if(isset($options['trusted_domains'])
162
		    && is_array($options['trusted_domains'])) {
163
			$trustedDomains = $options['trusted_domains'];
164
		} else {
165
			$trustedDomains = array(\OC_Request::getDomainWithoutPort(\OC_Request::serverHost()));
166
		}
167
168
		if (OC_Util::runningOnWindows()) {
169
			$dataDir = rtrim(realpath($dataDir), '\\');
170
		}
171
172
		//use sqlite3 when available, otherwise sqlite2 will be used.
173
		if($dbType=='sqlite' and class_exists('SQLite3')) {
174
			$dbType='sqlite3';
175
		}
176
177
		//generate a random salt that is used to salt the local user passwords
178
		$salt = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(30);
179
		// generate a secret
180
		$secret = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(48);
181
182
		//write the config file
183
		\OC::$server->getConfig()->setSystemValues([
184
			'passwordsalt'		=> $salt,
185
			'secret'			=> $secret,
186
			'trusted_domains'	=> $trustedDomains,
187
			'datadirectory'		=> $dataDir,
188
			'overwrite.cli.url'	=> \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost() . OC::$WEBROOT,
189
			'dbtype'			=> $dbType,
190
			'version'			=> implode('.', OC_Util::getVersion()),
191
		]);
192
193
		try {
194
			$dbSetup->initialize($options);
195
			$dbSetup->setupDatabase($username);
196
		} catch (\OC\DatabaseSetupException $e) {
197
			$error[] = array(
198
				'error' => $e->getMessage(),
199
				'hint' => $e->getHint()
200
			);
201
			return($error);
202
		} catch (Exception $e) {
203
			$error[] = array(
204
				'error' => 'Error while trying to create admin user: ' . $e->getMessage(),
205
				'hint' => ''
206
			);
207
			return($error);
208
		}
209
210
		//create the user and group
211
		try {
212
			OC_User::createUser($username, $password);
213
		} catch(Exception $exception) {
214
			$error[] = $exception->getMessage();
215
		}
216
217
		if(count($error) == 0) {
218
			$appConfig = \OC::$server->getAppConfig();
219
			$appConfig->setValue('core', 'installedat', microtime(true));
220
			$appConfig->setValue('core', 'lastupdatedat', microtime(true));
221
222
			OC_Group::createGroup('admin');
223
			OC_Group::addToGroup($username, 'admin');
224
			OC_User::login($username, $password);
225
226
			//guess what this does
227
			OC_Installer::installShippedApps();
228
229
			// create empty file in data dir, so we can later find
230
			// out that this is indeed an ownCloud data directory
231
			file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.ocdata', '');
232
233
			// Update htaccess files for apache hosts
234
			if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
235
				self::updateHtaccess();
236
				self::protectDataDirectory();
237
			}
238
239
			//and we are done
240
			OC_Config::setValue('installed', true);
241
		}
242
243
		return $error;
244
	}
245
246
	/**
247
	 * @return string Absolute path to htaccess
248
	 */
249
	private function pathToHtaccess() {
250
		return OC::$SERVERROOT.'/.htaccess';
251
	}
252
253
	/**
254
	 * Checks if the .htaccess contains the current version parameter
255
	 *
256
	 * @return bool
257
	 */
258
	private function isCurrentHtaccess() {
259
		$version = \OC_Util::getVersion();
260
		unset($version[3]);
261
262
		return !strpos(
263
			file_get_contents($this->pathToHtaccess()),
264
			'Version: '.implode('.', $version)
265
		) === false;
266
	}
267
268
	/**
269
	 * Append the correct ErrorDocument path for Apache hosts
270
	 *
271
	 * @throws \OC\HintException If .htaccess does not include the current version
272
	 */
273
	public static function updateHtaccess() {
274
		$setupHelper = new OC_Setup(\OC::$server->getConfig());
275
		if(!$setupHelper->isCurrentHtaccess()) {
276
			throw new \OC\HintException('.htaccess file has the wrong version. Please upload the correct version. Maybe you forgot to replace it after updating?');
277
		}
278
279
		$content = "\n";
280
		$content.= "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page
281
		$content.= "ErrorDocument 404 ".OC::$WEBROOT."/core/templates/404.php";//custom 404 error page
282
		@file_put_contents($setupHelper->pathToHtaccess(), $content, FILE_APPEND); //suppress errors in case we don't have permissions for it
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
283
	}
284
285
	public static function protectDataDirectory() {
286
		//Require all denied
287
		$now =  date('Y-m-d H:i:s');
288
		$content = "# Generated by ownCloud on $now\n";
289
		$content.= "# line below if for Apache 2.4\n";
290
		$content.= "<ifModule mod_authz_core.c>\n";
291
		$content.= "Require all denied\n";
292
		$content.= "</ifModule>\n\n";
293
		$content.= "# line below if for Apache 2.2\n";
294
		$content.= "<ifModule !mod_authz_core.c>\n";
295
		$content.= "deny from all\n";
296
		$content.= "</ifModule>\n\n";
297
		$content.= "# section for Apache 2.2 and 2.4\n";
298
		$content.= "IndexIgnore *\n";
299
		file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content);
300
		file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/index.html', '');
301
	}
302
}
303