Blame view

sources/apps/files_external/lib/config.php 28.7 KB
03e52840d   Kload   Init
1
2
3
4
5
6
  <?php
  /**
  * ownCloud
  *
  * @author Michael Gapczynski
  * @copyright 2012 Michael Gapczynski mtgap@owncloud.com
6d9380f96   Cédric Dupont   Update sources OC...
7
8
  * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
  * @copyright 2014 Robin McCorkell <rmccorkell@karoshi.org.uk>
03e52840d   Kload   Init
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  * License as published by the Free Software Foundation; either
  * version 3 of the License, or any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  *
  * You should have received a copy of the GNU Affero General Public
  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
  */
  
  /**
6d9380f96   Cédric Dupont   Update sources OC...
25
26
   * Class to configure mount.json globally and for users
   */
03e52840d   Kload   Init
27
  class OC_Mount_Config {
6d9380f96   Cédric Dupont   Update sources OC...
28
  	// TODO: make this class non-static and give it a proper namespace
03e52840d   Kload   Init
29
30
31
32
  
  	const MOUNT_TYPE_GLOBAL = 'global';
  	const MOUNT_TYPE_GROUP = 'group';
  	const MOUNT_TYPE_USER = 'user';
6d9380f96   Cédric Dupont   Update sources OC...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  	const MOUNT_TYPE_PERSONAL = 'personal';
  
  	// whether to skip backend test (for unit tests, as this static class is not mockable)
  	public static $skipTest = false;
  
  	private static $backends = array();
  
  	/**
  	 * @param string $class
  	 * @param array $definition
  	 * @return bool
  	 */
  	public static function registerBackend($class, $definition) {
  		if (!isset($definition['backend'])) {
  			return false;
  		}
  
  		OC_Mount_Config::$backends[$class] = $definition;
  		return true;
  	}
  
  	/**
  	 * Setup backends
  	 *
  	 * @return array of previously registered backends
  	 */
  	public static function setUp($backends = array()) {
  		$backup = self::$backends;
  		self::$backends = $backends;
  
  		return $backup;
  	}
03e52840d   Kload   Init
65
66
67
68
69
70
71
72
73
74
75
  
  	/**
  	* Get details on each of the external storage backends, used for the mount config UI
  	* If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded
  	* If the configuration parameter should be secret, add a '*' to the beginning of the value
  	* If the configuration parameter is a boolean, add a '!' to the beginning of the value
  	* If the configuration parameter is optional, add a '&' to the beginning of the value
  	* If the configuration parameter is hidden, add a '#' to the beginning of the value
  	* @return array
  	*/
  	public static function getBackends() {
6d9380f96   Cédric Dupont   Update sources OC...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  		$sortFunc = function($a, $b) {
  			return strcasecmp($a['backend'], $b['backend']);
  		};
  
  		$backEnds = array();
  
  		foreach (OC_Mount_Config::$backends as $class => $backend) {
  			if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) {
  				if (!method_exists($class, 'checkDependencies')) {
  					\OCP\Util::writeLog('files_external',
  						"Backend class $class has dependencies but doesn't provide method checkDependencies()",
  						\OCP\Util::DEBUG);
  					continue;
  				} elseif ($class::checkDependencies() !== true) {
  					continue;
  				}
  			}
  			$backEnds[$class] = $backend;
  		}
  
  		uasort($backEnds, $sortFunc);
  
  		return $backEnds;
  	}
  
  	/**
  	 * Hook that mounts the given user's visible mount points
  	 * @param array $data
  	 */
  	public static function initMountPointsHook($data) {
  		$mountPoints = self::getAbsoluteMountPoints($data['user']);
  		$loader = \OC\Files\Filesystem::getLoader();
  		$manager = \OC\Files\Filesystem::getMountManager();
  		foreach ($mountPoints as $mountPoint => $options) {
  			if (isset($options['options']['objectstore'])) {
  				$objectClass = $options['options']['objectstore']['class'];
  				$options['options']['objectstore'] = new $objectClass($options['options']['objectstore']);
  			}
  			if (isset($options['personal']) && $options['personal']) {
  				$mount = new \OCA\Files_External\PersonalMount($options['class'], $mountPoint, $options['options'], $loader);
  			} else{
  				$mount = new \OC\Files\Mount\Mount($options['class'], $mountPoint, $options['options'], $loader);
  			}
  			$manager->addMount($mount);
  		}
  	}
  
  	/**
  	 * Returns the mount points for the given user.
  	 * The mount point is relative to the data directory.
  	 *
  	 * @param string $user user
  	 * @return array of mount point string as key, mountpoint config as value
  	 */
  	public static function getAbsoluteMountPoints($user) {
  		$mountPoints = array();
  
  		$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
  		$mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json");
  
  		$backends = self::getBackends();
  
  		//move config file to it's new position
  		if (is_file(\OC::$SERVERROOT . '/config/mount.json')) {
  			rename(\OC::$SERVERROOT . '/config/mount.json', $mount_file);
  		}
  
  		// Load system mount points
  		$mountConfig = self::readData();
  
  		// Global mount points (is this redundant?)
  		if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) {
  			foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) {
  				$options['personal'] = false;
  				$options['options'] = self::decryptPasswords($options['options']);
  				if (!isset($options['priority'])) {
  					$options['priority'] = $backends[$options['class']]['priority'];
  				}
  
  				// Override if priority greater
  				if ( (!isset($mountPoints[$mountPoint]))
  					|| ($options['priority'] >= $mountPoints[$mountPoint]['priority']) ) {
  					$options['priority_type'] = self::MOUNT_TYPE_GLOBAL;
  					$options['backend'] = $backends[$options['class']]['backend'];
  					$mountPoints[$mountPoint] = $options;
  				}
  			}
  		}
  		// All user mount points
  		if (isset($mountConfig[self::MOUNT_TYPE_USER]) && isset($mountConfig[self::MOUNT_TYPE_USER]['all'])) {
  			$mounts = $mountConfig[self::MOUNT_TYPE_USER]['all'];
  			foreach ($mounts as $mountPoint => $options) {
  				$mountPoint = self::setUserVars($user, $mountPoint);
  				foreach ($options as &$option) {
  					$option = self::setUserVars($user, $option);
  				}
  				$options['options'] = self::decryptPasswords($options['options']);
  				if (!isset($options['priority'])) {
  					$options['priority'] = $backends[$options['class']]['priority'];
  				}
  
  				// Override if priority greater
  				if ( (!isset($mountPoints[$mountPoint]))
  					|| ($options['priority'] >= $mountPoints[$mountPoint]['priority']) ) {
  					$options['priority_type'] = self::MOUNT_TYPE_GLOBAL;
  					$options['backend'] = $backends[$options['class']]['backend'];
  					$mountPoints[$mountPoint] = $options;
  				}
  			}
  		}
  		// Group mount points
  		if (isset($mountConfig[self::MOUNT_TYPE_GROUP])) {
  			foreach ($mountConfig[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
  				if (\OC_Group::inGroup($user, $group)) {
  					foreach ($mounts as $mountPoint => $options) {
  						$mountPoint = self::setUserVars($user, $mountPoint);
  						foreach ($options as &$option) {
  							$option = self::setUserVars($user, $option);
  						}
  						$options['personal'] = false;
  						$options['options'] = self::decryptPasswords($options['options']);
  						if (!isset($options['priority'])) {
  							$options['priority'] = $backends[$options['class']]['priority'];
  						}
  
  						// Override if priority greater or if priority type different
  						if ( (!isset($mountPoints[$mountPoint]))
  							|| ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
  							|| ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_GROUP) ) {
  							$options['priority_type'] = self::MOUNT_TYPE_GROUP;
  							$options['backend'] = $backends[$options['class']]['backend'];
  							$mountPoints[$mountPoint] = $options;
  						}
  					}
  				}
  			}
  		}
  		// User mount points
  		if (isset($mountConfig[self::MOUNT_TYPE_USER])) {
  			foreach ($mountConfig[self::MOUNT_TYPE_USER] as $mountUser => $mounts) {
  				if (strtolower($mountUser) === strtolower($user)) {
  					foreach ($mounts as $mountPoint => $options) {
  						$mountPoint = self::setUserVars($user, $mountPoint);
  						foreach ($options as &$option) {
  							$option = self::setUserVars($user, $option);
  						}
  						$options['personal'] = false;
  						$options['options'] = self::decryptPasswords($options['options']);
  						if (!isset($options['priority'])) {
  							$options['priority'] = $backends[$options['class']]['priority'];
  						}
  
  						// Override if priority greater or if priority type different
  						if ( (!isset($mountPoints[$mountPoint]))
  							|| ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
  							|| ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_USER) ) {
  							$options['priority_type'] = self::MOUNT_TYPE_USER;
  							$options['backend'] = $backends[$options['class']]['backend'];
  							$mountPoints[$mountPoint] = $options;
  						}
  					}
  				}
  			}
  		}
  
  		// Load personal mount points
  		$mountConfig = self::readData($user);
  		if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) {
  			foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) {
  				$options['personal'] = true;
  				$options['options'] = self::decryptPasswords($options['options']);
  
  				// Always override previous config
  				$options['priority_type'] = self::MOUNT_TYPE_PERSONAL;
  				$options['backend'] = $backends[$options['class']]['backend'];
  				$mountPoints[$mountPoint] = $options;
  			}
  		}
  
  		return $mountPoints;
  	}
  
  	/**
  	 * fill in the correct values for $user
  	 *
  	 * @param string $user
  	 * @param string $input
  	 * @return string
  	 */
  	private static function setUserVars($user, $input) {
  		return str_replace('$user', $user, $input);
  	}
  
  
  	/**
  	* Get details on each of the external storage backends, used for the mount config UI
  	* Some backends are not available as a personal backend, f.e. Local and such that have
  	* been disabled by the admin.
  	*
  	* If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded
  	* If the configuration parameter should be secret, add a '*' to the beginning of the value
  	* If the configuration parameter is a boolean, add a '!' to the beginning of the value
  	* If the configuration parameter is optional, add a '&' to the beginning of the value
  	* If the configuration parameter is hidden, add a '#' to the beginning of the value
  	* @return array
  	*/
  	public static function getPersonalBackends() {
  
  		// Check whether the user has permissions to add personal storage backends
  		// return an empty array if this is not the case
  		if(OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') {
  			return array();
  		}
  
  		$backEnds = self::getBackends();
03e52840d   Kload   Init
291

6d9380f96   Cédric Dupont   Update sources OC...
292
293
294
295
296
297
298
  		// Remove local storage and other disabled storages
  		unset($backEnds['\OC\Files\Storage\Local']);
  
  		$allowedBackEnds = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', ''));
  		foreach ($backEnds as $backend => $null) {
  			if (!in_array($backend, $allowedBackEnds)) {
  				unset($backEnds[$backend]);
03e52840d   Kload   Init
299
300
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
301
  		return $backEnds;
03e52840d   Kload   Init
302
303
304
305
306
307
308
309
  	}
  
  	/**
  	* Get the system mount points
  	* The returned array is not in the same format as getUserMountPoints()
  	* @return array
  	*/
  	public static function getSystemMountPoints() {
6d9380f96   Cédric Dupont   Update sources OC...
310
  		$mountPoints = self::readData();
03e52840d   Kload   Init
311
312
313
314
315
316
317
318
319
  		$backends = self::getBackends();
  		$system = array();
  		if (isset($mountPoints[self::MOUNT_TYPE_GROUP])) {
  			foreach ($mountPoints[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
  				foreach ($mounts as $mountPoint => $mount) {
  					// Update old classes to new namespace
  					if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
  						$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
  					}
6d9380f96   Cédric Dupont   Update sources OC...
320
321
322
323
  					$mount['options'] = self::decryptPasswords($mount['options']);
  					if (!isset($mount['priority'])) {
  						$mount['priority'] = $backends[$mount['class']]['priority'];
  					}
03e52840d   Kload   Init
324
325
  					// Remove '/$user/files/' from mount point
  					$mountPoint = substr($mountPoint, 13);
6d9380f96   Cédric Dupont   Update sources OC...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  
  					$config = array(
  						'class' => $mount['class'],
  						'mountpoint' => $mountPoint,
  						'backend' => $backends[$mount['class']]['backend'],
  						'priority' => $mount['priority'],
  						'options' => $mount['options'],
  						'applicable' => array('groups' => array($group), 'users' => array()),
  						'status' => self::getBackendStatus($mount['class'], $mount['options'], false)
  					);
  					$hash = self::makeConfigHash($config);
  					// If an existing config exists (with same class, mountpoint and options)
  					if (isset($system[$hash])) {
  						// add the groups into that config
  						$system[$hash]['applicable']['groups']
  							= array_merge($system[$hash]['applicable']['groups'], array($group));
03e52840d   Kload   Init
342
  					} else {
6d9380f96   Cédric Dupont   Update sources OC...
343
  						$system[$hash] = $config;
03e52840d   Kload   Init
344
345
346
347
348
349
350
351
352
353
354
  					}
  				}
  			}
  		}
  		if (isset($mountPoints[self::MOUNT_TYPE_USER])) {
  			foreach ($mountPoints[self::MOUNT_TYPE_USER] as $user => $mounts) {
  				foreach ($mounts as $mountPoint => $mount) {
  					// Update old classes to new namespace
  					if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
  						$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
  					}
6d9380f96   Cédric Dupont   Update sources OC...
355
356
357
358
  					$mount['options'] = self::decryptPasswords($mount['options']);
  					if (!isset($mount['priority'])) {
  						$mount['priority'] = $backends[$mount['class']]['priority'];
  					}
03e52840d   Kload   Init
359
360
  					// Remove '/$user/files/' from mount point
  					$mountPoint = substr($mountPoint, 13);
6d9380f96   Cédric Dupont   Update sources OC...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  					$config = array(
  						'class' => $mount['class'],
  						'mountpoint' => $mountPoint,
  						'backend' => $backends[$mount['class']]['backend'],
  						'priority' => $mount['priority'],
  						'options' => $mount['options'],
  						'applicable' => array('groups' => array(), 'users' => array($user)),
  						'status' => self::getBackendStatus($mount['class'], $mount['options'], false)
  					);
  					$hash = self::makeConfigHash($config);
  					// If an existing config exists (with same class, mountpoint and options)
  					if (isset($system[$hash])) {
  						// add the users into that config
  						$system[$hash]['applicable']['users']
  							= array_merge($system[$hash]['applicable']['users'], array($user));
03e52840d   Kload   Init
376
  					} else {
6d9380f96   Cédric Dupont   Update sources OC...
377
  						$system[$hash] = $config;
03e52840d   Kload   Init
378
379
380
381
  					}
  				}
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
382
  		return array_values($system);
03e52840d   Kload   Init
383
384
385
386
387
388
389
390
  	}
  
  	/**
  	* Get the personal mount points of the current user
  	* The returned array is not in the same format as getUserMountPoints()
  	* @return array
  	*/
  	public static function getPersonalMountPoints() {
6d9380f96   Cédric Dupont   Update sources OC...
391
392
  		$mountPoints = self::readData(OCP\User::getUser());
  		$backEnds = self::getBackends();
03e52840d   Kload   Init
393
394
395
396
397
398
399
400
  		$uid = OCP\User::getUser();
  		$personal = array();
  		if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) {
  			foreach ($mountPoints[self::MOUNT_TYPE_USER][$uid] as $mountPoint => $mount) {
  				// Update old classes to new namespace
  				if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
  					$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
  				}
6d9380f96   Cédric Dupont   Update sources OC...
401
402
  				$mount['options'] = self::decryptPasswords($mount['options']);
  				$personal[] = array(
03e52840d   Kload   Init
403
  					'class' => $mount['class'],
6d9380f96   Cédric Dupont   Update sources OC...
404
405
406
407
408
  					// Remove '/uid/files/' from mount point
  					'mountpoint' => substr($mountPoint, strlen($uid) + 8),
  					'backend' => $backEnds[$mount['class']]['backend'],
  					'options' => $mount['options'],
  					'status' => self::getBackendStatus($mount['class'], $mount['options'], true)
03e52840d   Kload   Init
409
410
411
412
413
  				);
  			}
  		}
  		return $personal;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
414
415
416
417
418
419
420
421
422
423
  	/**
  	 * Test connecting using the given backend configuration
  	 * @param string $class backend class name
  	 * @param array $options backend configuration options
  	 * @return bool true if the connection succeeded, false otherwise
  	 */
  	private static function getBackendStatus($class, $options, $isPersonal) {
  		if (self::$skipTest) {
  			return true;
  		}
03e52840d   Kload   Init
424
  		foreach ($options as &$option) {
6d9380f96   Cédric Dupont   Update sources OC...
425
  			$option = self::setUserVars(OCP\User::getUser(), $option);
03e52840d   Kload   Init
426
427
428
429
  		}
  		if (class_exists($class)) {
  			try {
  				$storage = new $class($options);
6d9380f96   Cédric Dupont   Update sources OC...
430
  				return $storage->test($isPersonal);
03e52840d   Kload   Init
431
  			} catch (Exception $exception) {
31b7f2792   Kload   Upgrade to ownclo...
432
  				\OCP\Util::logException('files_external', $exception);
03e52840d   Kload   Init
433
434
435
436
437
438
439
440
  				return false;
  			}
  		}
  		return false;
  	}
  
  	/**
  	* Add a mount point to the filesystem
6d9380f96   Cédric Dupont   Update sources OC...
441
442
443
444
445
446
447
448
  	* @param string $mountPoint Mount point
  	* @param string $class Backend class
  	* @param array $classOptions Backend parameters for the class
  	* @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
  	* @param string $applicable User or group to apply mount to
  	* @param bool $isPersonal Personal or system mount point i.e. is this being called from the personal or admin page
  	* @param int|null $priority Mount point priority, null for default
  	* @return boolean
03e52840d   Kload   Init
449
450
451
452
453
454
  	*/
  	public static function addMountPoint($mountPoint,
  										 $class,
  										 $classOptions,
  										 $mountType,
  										 $applicable,
6d9380f96   Cédric Dupont   Update sources OC...
455
456
  										 $isPersonal = false,
  										 $priority = null) {
a293d369c   Kload   Update sources to...
457
  		$backends = self::getBackends();
31b7f2792   Kload   Upgrade to ownclo...
458
  		$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
6d9380f96   Cédric Dupont   Update sources OC...
459
460
  		if ($mountPoint === '' || $mountPoint === '/') {
  			// can't mount at root folder
31b7f2792   Kload   Upgrade to ownclo...
461
462
  			return false;
  		}
a293d369c   Kload   Update sources to...
463
464
465
466
  
  		if (!isset($backends[$class])) {
  			// invalid backend
  			return false;
6d9380f96   Cédric Dupont   Update sources OC...
467
  		}
03e52840d   Kload   Init
468
469
  		if ($isPersonal) {
  			// Verify that the mount point applies for the current user
6d9380f96   Cédric Dupont   Update sources OC...
470
471
472
  			// Prevent non-admin users from mounting local storage and other disabled backends
  			$allowed_backends = self::getPersonalBackends();
  			if ($applicable != OCP\User::getUser() || !isset($allowed_backends[$class])) {
03e52840d   Kload   Init
473
474
475
476
477
478
  				return false;
  			}
  			$mountPoint = '/'.$applicable.'/files/'.ltrim($mountPoint, '/');
  		} else {
  			$mountPoint = '/$user/files/'.ltrim($mountPoint, '/');
  		}
6d9380f96   Cédric Dupont   Update sources OC...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  
  		$mount = array($applicable => array(
  			$mountPoint => array(
  				'class' => $class,
  				'options' => self::encryptPasswords($classOptions))
  			)
  		);
  		if (! $isPersonal && !is_null($priority)) {
  			$mount[$applicable][$mountPoint]['priority'] = $priority;
  		}
  
  		$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : NULL);
  		$mountPoints = self::mergeMountPoints($mountPoints, $mount, $mountType);
  
  		// Set default priority if none set
  		if (!isset($mountPoints[$mountType][$applicable][$mountPoint]['priority'])) {
  			if (isset($backends[$class]['priority'])) {
  				$mountPoints[$mountType][$applicable][$mountPoint]['priority']
  					= $backends[$class]['priority'];
03e52840d   Kload   Init
498
  			} else {
6d9380f96   Cédric Dupont   Update sources OC...
499
500
  				$mountPoints[$mountType][$applicable][$mountPoint]['priority']
  					= 100;
03e52840d   Kload   Init
501
  			}
03e52840d   Kload   Init
502
  		}
6d9380f96   Cédric Dupont   Update sources OC...
503
504
505
506
  
  		self::writeData($isPersonal ? OCP\User::getUser() : NULL, $mountPoints);
  
  		return self::getBackendStatus($class, $classOptions, $isPersonal);
03e52840d   Kload   Init
507
508
509
510
  	}
  
  	/**
  	*
6d9380f96   Cédric Dupont   Update sources OC...
511
512
513
514
  	* @param string $mountPoint Mount point
  	* @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
  	* @param string $applicable User or group to remove mount from
  	* @param bool $isPersonal Personal or system mount point
03e52840d   Kload   Init
515
516
517
518
519
520
521
522
523
524
525
526
  	* @return bool
  	*/
  	public static function removeMountPoint($mountPoint, $mountType, $applicable, $isPersonal = false) {
  		// Verify that the mount point applies for the current user
  		if ($isPersonal) {
  			if ($applicable != OCP\User::getUser()) {
  				return false;
  			}
  			$mountPoint = '/'.$applicable.'/files/'.ltrim($mountPoint, '/');
  		} else {
  			$mountPoint = '/$user/files/'.ltrim($mountPoint, '/');
  		}
6d9380f96   Cédric Dupont   Update sources OC...
527
528
  		$mountPoint = \OC\Files\Filesystem::normalizePath($mountPoint);
  		$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : NULL);
03e52840d   Kload   Init
529
530
531
532
533
534
535
536
537
  		// Remove mount point
  		unset($mountPoints[$mountType][$applicable][$mountPoint]);
  		// Unset parent arrays if empty
  		if (empty($mountPoints[$mountType][$applicable])) {
  			unset($mountPoints[$mountType][$applicable]);
  			if (empty($mountPoints[$mountType])) {
  				unset($mountPoints[$mountType]);
  			}
  		}
6d9380f96   Cédric Dupont   Update sources OC...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
  		self::writeData($isPersonal ? OCP\User::getUser() : NULL, $mountPoints);
  		return true;
  	}
  
  	/**
  	 *
  	 * @param string $mountPoint Mount point
  	 * @param string $target The new mount point
  	 * @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
  	 * @return bool
  	 */
  	public static function movePersonalMountPoint($mountPoint, $target, $mountType) {
  		$mountPoint = rtrim($mountPoint, '/');
  		$user = OCP\User::getUser();
  		$mountPoints = self::readData($user);
  		if (!isset($mountPoints[$mountType][$user][$mountPoint])) {
  			return false;
  		}
  		$mountPoints[$mountType][$user][$target] = $mountPoints[$mountType][$user][$mountPoint];
  		// Remove old mount point
  		unset($mountPoints[$mountType][$user][$mountPoint]);
  
  		self::writeData($user, $mountPoints);
03e52840d   Kload   Init
561
562
563
564
565
  		return true;
  	}
  
  	/**
  	* Read the mount points in the config file into an array
6d9380f96   Cédric Dupont   Update sources OC...
566
  	* @param string|null $user If not null, personal for $user, otherwise system
03e52840d   Kload   Init
567
568
  	* @return array
  	*/
6d9380f96   Cédric Dupont   Update sources OC...
569
  	private static function readData($user = NULL) {
03e52840d   Kload   Init
570
  		$parser = new \OC\ArrayParser();
6d9380f96   Cédric Dupont   Update sources OC...
571
572
573
  		if (isset($user)) {
  			$phpFile = OC_User::getHome($user).'/mount.php';
  			$jsonFile = OC_User::getHome($user).'/mount.json';
03e52840d   Kload   Init
574
  		} else {
03e52840d   Kload   Init
575
  			$phpFile = OC::$SERVERROOT.'/config/mount.php';
6d9380f96   Cédric Dupont   Update sources OC...
576
577
  			$datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data/');
  			$jsonFile = \OC_Config::getValue('mount_file', $datadir . '/mount.json');
03e52840d   Kload   Init
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
  		}
  		if (is_file($jsonFile)) {
  			$mountPoints = json_decode(file_get_contents($jsonFile), true);
  			if (is_array($mountPoints)) {
  				return $mountPoints;
  			}
  		} elseif (is_file($phpFile)) {
  			$mountPoints = $parser->parsePHP(file_get_contents($phpFile));
  			if (is_array($mountPoints)) {
  				return $mountPoints;
  			}
  		}
  		return array();
  	}
  
  	/**
  	* Write the mount points to the config file
6d9380f96   Cédric Dupont   Update sources OC...
595
596
  	* @param string|null $user If not null, personal for $user, otherwise system
  	* @param array $data Mount points
03e52840d   Kload   Init
597
  	*/
6d9380f96   Cédric Dupont   Update sources OC...
598
599
600
  	private static function writeData($user, $data) {
  		if (isset($user)) {
  			$file = OC_User::getHome($user).'/mount.json';
03e52840d   Kload   Init
601
  		} else {
6d9380f96   Cédric Dupont   Update sources OC...
602
603
604
605
606
607
608
  			$datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data/');
  			$file = \OC_Config::getValue('mount_file', $datadir . '/mount.json');
  		}
  		$options = 0;
  		if (defined('JSON_PRETTY_PRINT')) {
  			// only for PHP >= 5.4
  			$options = JSON_PRETTY_PRINT;
03e52840d   Kload   Init
609
  		}
6d9380f96   Cédric Dupont   Update sources OC...
610
  		$content = json_encode($data, $options);
03e52840d   Kload   Init
611
  		@file_put_contents($file, $content);
31b7f2792   Kload   Upgrade to ownclo...
612
  		@chmod($file, 0640);
03e52840d   Kload   Init
613
614
615
616
617
618
619
  	}
  
  	/**
  	 * Returns all user uploaded ssl root certificates
  	 * @return array
  	 */
  	public static function getCertificates() {
a293d369c   Kload   Update sources to...
620
  		$path=OC_User::getHome(OC_User::getUser()) . '/files_external/uploads/';
03e52840d   Kload   Init
621
622
623
624
625
626
627
628
  		\OCP\Util::writeLog('files_external', 'checking path '.$path, \OCP\Util::INFO);
  		if ( ! is_dir($path)) {
  			//path might not exist (e.g. non-standard OC_User::getHome() value)
  			//in this case create full path using 3rd (recursive=true) parameter.
  			mkdir($path, 0777, true);
  		}
  		$result = array();
  		$handle = opendir($path);
31b7f2792   Kload   Upgrade to ownclo...
629
  		if(!is_resource($handle)) {
03e52840d   Kload   Init
630
631
632
633
634
635
636
637
638
639
640
641
  			return array();
  		}
  		while (false !== ($file = readdir($handle))) {
  			if ($file != '.' && $file != '..') $result[] = $file;
  		}
  		return $result;
  	}
  
  	/**
  	 * creates certificate bundle
  	 */
  	public static function createCertificateBundle() {
a293d369c   Kload   Update sources to...
642
  		$path=OC_User::getHome(OC_User::getUser()) . '/files_external';
03e52840d   Kload   Init
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
  
  		$certs = OC_Mount_Config::getCertificates();
  		$fh_certs = fopen($path."/rootcerts.crt", 'w');
  		foreach ($certs as $cert) {
  			$file=$path.'/uploads/'.$cert;
  			$fh = fopen($file, "r");
  			$data = fread($fh, filesize($file));
  			fclose($fh);
  			if (strpos($data, 'BEGIN CERTIFICATE')) {
  				fwrite($fh_certs, $data);
  				fwrite($fh_certs, "\r
  ");
  			}
  		}
  
  		fclose($fh_certs);
  
  		return true;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
664
  	 * check dependencies
03e52840d   Kload   Init
665
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  	public static function checkDependencies() {
  		$dependencies = array();
  		foreach (OC_Mount_Config::$backends as $class => $backend) {
  			if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) {
  				$result = $class::checkDependencies();
  				if ($result !== true) {
  					if (!is_array($result)) {
  						$result = array($result);
  					}
  					foreach ($result as $key => $value) {
  						if (is_numeric($key)) {
  							OC_Mount_Config::addDependency($dependencies, $value, $backend['backend']);
  						} else {
  							OC_Mount_Config::addDependency($dependencies, $key, $backend['backend'], $value);
  						}
  					}
  				}
  			}
  		}
  
  		if (count($dependencies) > 0) {
  			return OC_Mount_Config::generateDependencyMessage($dependencies);
03e52840d   Kload   Init
688
  		}
6d9380f96   Cédric Dupont   Update sources OC...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  		return '';
  	}
  
  	private static function addDependency(&$dependencies, $module, $backend, $message=null) {
  		if (!isset($dependencies[$module])) {
  			$dependencies[$module] = array();
  		}
  
  		if ($message === null) {
  			$dependencies[$module][] = $backend;
  		} else {
  			$dependencies[$module][] = array('backend' => $backend, 'message' => $message);
  		}
  	}
  
  	private static function generateDependencyMessage($dependencies) {
  		$l = new \OC_L10N('files_external');
  		$dependencyMessage = '';
  		foreach ($dependencies as $module => $backends) {
  			$dependencyGroup = array();
  			foreach ($backends as $backend) {
  				if (is_array($backend)) {
  					$dependencyMessage .= '<br />' . $l->t('<b>Note:</b> ') . $backend['message'];
  				} else {
  					$dependencyGroup[] = $backend;
  				}
  			}
  
  			if (count($dependencyGroup) > 0) {
  				$backends = '';
  				for ($i = 0; $i < count($dependencyGroup); $i++) {
  					if ($i > 0 && $i === count($dependencyGroup) - 1) {
  						$backends .= $l->t(' and ');
  					} elseif ($i > 0) {
  						$backends .= ', ';
  					}
  					$backends .= '<i>' . $dependencyGroup[$i] . '</i>';
  				}
  				$dependencyMessage .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends);
  			}
  		}
  		return $dependencyMessage;
03e52840d   Kload   Init
731
732
733
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
734
735
736
737
738
  	 * Returns a dependency missing message
  	 * @param OC_L10N $l
  	 * @param string $module
  	 * @param string $backend
  	 * @return string
03e52840d   Kload   Init
739
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
740
741
742
743
744
745
746
747
  	private static function getSingleDependencyMessage($l, $module, $backend) {
  		switch (strtolower($module)) {
  			case 'curl':
  				return $l->t('<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', $backend);
  			case 'ftp':
  				return $l->t('<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', $backend);
  			default:
  				return $l->t('<b>Note:</b> "%s" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it.', array($module, $backend));
03e52840d   Kload   Init
748
749
750
751
  		}
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
752
753
754
  	 * Encrypt passwords in the given config options
  	 * @param array $options mount options
  	 * @return array updated options
31b7f2792   Kload   Upgrade to ownclo...
755
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
756
757
758
759
760
761
762
763
  	private static function encryptPasswords($options) {
  		if (isset($options['password'])) {
  			$options['password_encrypted'] = self::encryptPassword($options['password']);
  			// do not unset the password, we want to keep the keys order
  			// on load... because that's how the UI currently works
  			$options['password'] = '';
  		}
  		return $options;
31b7f2792   Kload   Upgrade to ownclo...
764
765
766
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
767
768
769
  	 * Decrypt passwords in the given config options
  	 * @param array $options mount options
  	 * @return array updated options
03e52840d   Kload   Init
770
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
771
772
773
774
775
  	private static function decryptPasswords($options) {
  		// note: legacy options might still have the unencrypted password in the "password" field
  		if (isset($options['password_encrypted'])) {
  			$options['password'] = self::decryptPassword($options['password_encrypted']);
  			unset($options['password_encrypted']);
03e52840d   Kload   Init
776
  		}
6d9380f96   Cédric Dupont   Update sources OC...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
  		return $options;
  	}
  
  	/**
  	 * Encrypt a single password
  	 * @param string $password plain text password
  	 * @return string encrypted password
  	 */
  	private static function encryptPassword($password) {
  		$cipher = self::getCipher();
  		$iv = \OCP\Util::generateRandomBytes(16);
  		$cipher->setIV($iv);
  		return base64_encode($iv . $cipher->encrypt($password));
  	}
  
  	/**
  	 * Decrypts a single password
  	 * @param string $encryptedPassword encrypted password
  	 * @return string plain text password
  	 */
  	private static function decryptPassword($encryptedPassword) {
  		$cipher = self::getCipher();
  		$binaryPassword = base64_decode($encryptedPassword);
  		$iv = substr($binaryPassword, 0, 16);
  		$cipher->setIV($iv);
  		$binaryPassword = substr($binaryPassword, 16);
  		return $cipher->decrypt($binaryPassword);
  	}
  
  	/**
  	 * Merges mount points
  	 * @param array $data Existing mount points
  	 * @param array $mountPoint New mount point
  	 * @param string $mountType
  	 * @return array
  	 */
  	private static function mergeMountPoints($data, $mountPoint, $mountType) {
  		$applicable = key($mountPoint);
  		$mountPath = key($mountPoint[$applicable]);
  		if (isset($data[$mountType])) {
  			if (isset($data[$mountType][$applicable])) {
  				// Merge priorities
  				if (isset($data[$mountType][$applicable][$mountPath])
  					&& isset($data[$mountType][$applicable][$mountPath]['priority'])
  					&& !isset($mountPoint[$applicable][$mountPath]['priority'])) {
  					$mountPoint[$applicable][$mountPath]['priority']
  						= $data[$mountType][$applicable][$mountPath]['priority'];
  				}
  				$data[$mountType][$applicable]
  					= array_merge($data[$mountType][$applicable], $mountPoint[$applicable]);
  			} else {
  				$data[$mountType] = array_merge($data[$mountType], $mountPoint);
  			}
  		} else {
  			$data[$mountType] = $mountPoint;
03e52840d   Kload   Init
832
  		}
6d9380f96   Cédric Dupont   Update sources OC...
833
834
835
836
837
838
839
840
841
  		return $data;
  	}
  
  	/**
  	 * Returns the encryption cipher
  	 */
  	private static function getCipher() {
  		if (!class_exists('Crypt_AES', false)) {
  			include('Crypt/AES.php');
31b7f2792   Kload   Upgrade to ownclo...
842
  		}
6d9380f96   Cédric Dupont   Update sources OC...
843
844
845
846
  		$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
  		$cipher->setKey(\OCP\Config::getSystemValue('passwordsalt'));
  		return $cipher;
  	}
03e52840d   Kload   Init
847

6d9380f96   Cédric Dupont   Update sources OC...
848
849
850
851
852
853
854
855
856
857
858
859
860
861
  	/**
  	 * Computes a hash based on the given configuration.
  	 * This is mostly used to find out whether configurations
  	 * are the same.
  	 */
  	private static function makeConfigHash($config) {
  		$data = json_encode(
  			array(
  				'c' => $config['class'],
  				'm' => $config['mountpoint'],
  				'o' => $config['options']
  			)
  		);
  		return hash('md5', $data);
03e52840d   Kload   Init
862
863
  	}
  }