Completed
Push — master ( 26682b...01d362 )
by Morris
131:00 queued 110:46
created
settings/Controller/AppSettingsController.php 2 patches
Indentation   +411 added lines, -411 removed lines patch added patch discarded remove patch
@@ -53,415 +53,415 @@
 block discarded – undo
53 53
  * @package OC\Settings\Controller
54 54
  */
55 55
 class AppSettingsController extends Controller {
56
-	const CAT_ENABLED = 0;
57
-	const CAT_DISABLED = 1;
58
-	const CAT_ALL_INSTALLED = 2;
59
-	const CAT_APP_BUNDLES = 3;
60
-	const CAT_UPDATES = 4;
61
-
62
-	/** @var \OCP\IL10N */
63
-	private $l10n;
64
-	/** @var IConfig */
65
-	private $config;
66
-	/** @var INavigationManager */
67
-	private $navigationManager;
68
-	/** @var IAppManager */
69
-	private $appManager;
70
-	/** @var CategoryFetcher */
71
-	private $categoryFetcher;
72
-	/** @var AppFetcher */
73
-	private $appFetcher;
74
-	/** @var IFactory */
75
-	private $l10nFactory;
76
-	/** @var BundleFetcher */
77
-	private $bundleFetcher;
78
-	/** @var Installer */
79
-	private $installer;
80
-
81
-	/**
82
-	 * @param string $appName
83
-	 * @param IRequest $request
84
-	 * @param IL10N $l10n
85
-	 * @param IConfig $config
86
-	 * @param INavigationManager $navigationManager
87
-	 * @param IAppManager $appManager
88
-	 * @param CategoryFetcher $categoryFetcher
89
-	 * @param AppFetcher $appFetcher
90
-	 * @param IFactory $l10nFactory
91
-	 * @param BundleFetcher $bundleFetcher
92
-	 * @param Installer $installer
93
-	 */
94
-	public function __construct($appName,
95
-								IRequest $request,
96
-								IL10N $l10n,
97
-								IConfig $config,
98
-								INavigationManager $navigationManager,
99
-								IAppManager $appManager,
100
-								CategoryFetcher $categoryFetcher,
101
-								AppFetcher $appFetcher,
102
-								IFactory $l10nFactory,
103
-								BundleFetcher $bundleFetcher,
104
-								Installer $installer) {
105
-		parent::__construct($appName, $request);
106
-		$this->l10n = $l10n;
107
-		$this->config = $config;
108
-		$this->navigationManager = $navigationManager;
109
-		$this->appManager = $appManager;
110
-		$this->categoryFetcher = $categoryFetcher;
111
-		$this->appFetcher = $appFetcher;
112
-		$this->l10nFactory = $l10nFactory;
113
-		$this->bundleFetcher = $bundleFetcher;
114
-		$this->installer = $installer;
115
-	}
116
-
117
-	/**
118
-	 * @NoCSRFRequired
119
-	 *
120
-	 * @param string $category
121
-	 * @return TemplateResponse
122
-	 */
123
-	public function viewApps($category = '') {
124
-		if ($category === '') {
125
-			$category = 'installed';
126
-		}
127
-
128
-		$params = [];
129
-		$params['category'] = $category;
130
-		$params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
131
-		$this->navigationManager->setActiveEntry('core_apps');
132
-
133
-		$templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user');
134
-		$policy = new ContentSecurityPolicy();
135
-		$policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');
136
-		$templateResponse->setContentSecurityPolicy($policy);
137
-
138
-		return $templateResponse;
139
-	}
140
-
141
-	private function getAllCategories() {
142
-		$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
143
-
144
-		$updateCount = count($this->getAppsWithUpdates());
145
-		$formattedCategories = [
146
-			['id' => self::CAT_ALL_INSTALLED, 'ident' => 'installed', 'displayName' => (string)$this->l10n->t('Your apps')],
147
-			['id' => self::CAT_UPDATES, 'ident' => 'updates', 'displayName' => (string)$this->l10n->t('Updates'), 'counter' => $updateCount],
148
-			['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled apps')],
149
-			['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Disabled apps')],
150
-			['id' => self::CAT_APP_BUNDLES, 'ident' => 'app-bundles', 'displayName' => (string)$this->l10n->t('App bundles')],
151
-		];
152
-		$categories = $this->categoryFetcher->get();
153
-		foreach($categories as $category) {
154
-			$formattedCategories[] = [
155
-				'id' => $category['id'],
156
-				'ident' => $category['id'],
157
-				'displayName' => isset($category['translations'][$currentLanguage]['name']) ? $category['translations'][$currentLanguage]['name'] : $category['translations']['en']['name'],
158
-			];
159
-		}
160
-
161
-		return $formattedCategories;
162
-	}
163
-
164
-	/**
165
-	 * Get all available categories
166
-	 *
167
-	 * @return JSONResponse
168
-	 */
169
-	public function listCategories() {
170
-		return new JSONResponse($this->getAllCategories());
171
-	}
172
-
173
-	/**
174
-	 * Get all apps for a category
175
-	 *
176
-	 * @param string $requestedCategory
177
-	 * @return array
178
-	 */
179
-	private function getAppsForCategory($requestedCategory) {
180
-		$versionParser = new VersionParser();
181
-		$formattedApps = [];
182
-		$apps = $this->appFetcher->get();
183
-		foreach($apps as $app) {
184
-			if (isset($app['isFeatured'])) {
185
-				$app['featured'] = $app['isFeatured'];
186
-			}
187
-
188
-			// Skip all apps not in the requested category
189
-			$isInCategory = false;
190
-			foreach($app['categories'] as $category) {
191
-				if($category === $requestedCategory) {
192
-					$isInCategory = true;
193
-				}
194
-			}
195
-			if(!$isInCategory) {
196
-				continue;
197
-			}
198
-
199
-			$nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
200
-			$nextCloudVersionDependencies = [];
201
-			if($nextCloudVersion->getMinimumVersion() !== '') {
202
-				$nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
203
-			}
204
-			if($nextCloudVersion->getMaximumVersion() !== '') {
205
-				$nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
206
-			}
207
-			$phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
208
-			$existsLocally = \OC_App::getAppPath($app['id']) !== false;
209
-			$phpDependencies = [];
210
-			if($phpVersion->getMinimumVersion() !== '') {
211
-				$phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
212
-			}
213
-			if($phpVersion->getMaximumVersion() !== '') {
214
-				$phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
215
-			}
216
-			if(isset($app['releases'][0]['minIntSize'])) {
217
-				$phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
218
-			}
219
-			$authors = '';
220
-			foreach($app['authors'] as $key => $author) {
221
-				$authors .= $author['name'];
222
-				if($key !== count($app['authors']) - 1) {
223
-					$authors .= ', ';
224
-				}
225
-			}
226
-
227
-			$currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
228
-			$enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
229
-			$groups = null;
230
-			if($enabledValue !== 'no' && $enabledValue !== 'yes') {
231
-				$groups = $enabledValue;
232
-			}
233
-
234
-			$currentVersion = '';
235
-			if($this->appManager->isInstalled($app['id'])) {
236
-				$currentVersion = \OC_App::getAppVersion($app['id']);
237
-			} else {
238
-				$currentLanguage = $app['releases'][0]['version'];
239
-			}
240
-
241
-			$formattedApps[] = [
242
-				'id' => $app['id'],
243
-				'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'],
244
-				'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'],
245
-				'license' => $app['releases'][0]['licenses'],
246
-				'author' => $authors,
247
-				'shipped' => false,
248
-				'version' => $currentVersion,
249
-				'default_enable' => '',
250
-				'types' => [],
251
-				'documentation' => [
252
-					'admin' => $app['adminDocs'],
253
-					'user' => $app['userDocs'],
254
-					'developer' => $app['developerDocs']
255
-				],
256
-				'website' => $app['website'],
257
-				'bugs' => $app['issueTracker'],
258
-				'detailpage' => $app['website'],
259
-				'dependencies' => array_merge(
260
-					$nextCloudVersionDependencies,
261
-					$phpDependencies
262
-				),
263
-				'level' => ($app['featured'] === true) ? 200 : 100,
264
-				'missingMaxOwnCloudVersion' => false,
265
-				'missingMinOwnCloudVersion' => false,
266
-				'canInstall' => true,
267
-				'preview' => isset($app['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($app['screenshots'][0]['url']) : '',
268
-				'score' => $app['ratingOverall'],
269
-				'ratingNumOverall' => $app['ratingNumOverall'],
270
-				'ratingNumThresholdReached' => $app['ratingNumOverall'] > 5 ? true : false,
271
-				'removable' => $existsLocally,
272
-				'active' => $this->appManager->isEnabledForUser($app['id']),
273
-				'needsDownload' => !$existsLocally,
274
-				'groups' => $groups,
275
-				'fromAppStore' => true,
276
-			];
277
-
278
-
279
-			$newVersion = $this->installer->isUpdateAvailable($app['id']);
280
-			if($newVersion && $this->appManager->isInstalled($app['id'])) {
281
-				$formattedApps[count($formattedApps)-1]['update'] = $newVersion;
282
-			}
283
-		}
284
-
285
-		return $formattedApps;
286
-	}
287
-
288
-	private function getAppsWithUpdates() {
289
-		$appClass = new \OC_App();
290
-		$apps = $appClass->listAllApps();
291
-		foreach($apps as $key => $app) {
292
-			$newVersion = $this->installer->isUpdateAvailable($app['id']);
293
-			if($newVersion !== false) {
294
-				$apps[$key]['update'] = $newVersion;
295
-			} else {
296
-				unset($apps[$key]);
297
-			}
298
-		}
299
-		usort($apps, function ($a, $b) {
300
-			$a = (string)$a['name'];
301
-			$b = (string)$b['name'];
302
-			if ($a === $b) {
303
-				return 0;
304
-			}
305
-			return ($a < $b) ? -1 : 1;
306
-		});
307
-		return $apps;
308
-	}
309
-
310
-	/**
311
-	 * Get all available apps in a category
312
-	 *
313
-	 * @param string $category
314
-	 * @return JSONResponse
315
-	 */
316
-	public function listApps($category = '') {
317
-		$appClass = new \OC_App();
318
-
319
-		switch ($category) {
320
-			// installed apps
321
-			case 'installed':
322
-				$apps = $appClass->listAllApps();
323
-
324
-				foreach($apps as $key => $app) {
325
-					$newVersion = $this->installer->isUpdateAvailable($app['id']);
326
-					$apps[$key]['update'] = $newVersion;
327
-				}
328
-
329
-				usort($apps, function ($a, $b) {
330
-					$a = (string)$a['name'];
331
-					$b = (string)$b['name'];
332
-					if ($a === $b) {
333
-						return 0;
334
-					}
335
-					return ($a < $b) ? -1 : 1;
336
-				});
337
-				break;
338
-			// updates
339
-			case 'updates':
340
-				$apps = $this->getAppsWithUpdates();
341
-				break;
342
-			// enabled apps
343
-			case 'enabled':
344
-				$apps = $appClass->listAllApps();
345
-				$apps = array_filter($apps, function ($app) {
346
-					return $app['active'];
347
-				});
348
-
349
-				foreach($apps as $key => $app) {
350
-					$newVersion = $this->installer->isUpdateAvailable($app['id']);
351
-					$apps[$key]['update'] = $newVersion;
352
-				}
353
-
354
-				usort($apps, function ($a, $b) {
355
-					$a = (string)$a['name'];
356
-					$b = (string)$b['name'];
357
-					if ($a === $b) {
358
-						return 0;
359
-					}
360
-					return ($a < $b) ? -1 : 1;
361
-				});
362
-				break;
363
-			// disabled  apps
364
-			case 'disabled':
365
-				$apps = $appClass->listAllApps();
366
-				$apps = array_filter($apps, function ($app) {
367
-					return !$app['active'];
368
-				});
369
-
370
-				$apps = array_map(function ($app) {
371
-					$newVersion = $this->installer->isUpdateAvailable($app['id']);
372
-					if ($newVersion !== false) {
373
-						$app['update'] = $newVersion;
374
-					}
375
-					return $app;
376
-				}, $apps);
377
-
378
-				usort($apps, function ($a, $b) {
379
-					$a = (string)$a['name'];
380
-					$b = (string)$b['name'];
381
-					if ($a === $b) {
382
-						return 0;
383
-					}
384
-					return ($a < $b) ? -1 : 1;
385
-				});
386
-				break;
387
-			case 'app-bundles':
388
-				$bundles = $this->bundleFetcher->getBundles();
389
-				$apps = [];
390
-				foreach($bundles as $bundle) {
391
-					$newCategory = true;
392
-					$allApps = $appClass->listAllApps();
393
-					$categories = $this->getAllCategories();
394
-					foreach($categories as $singleCategory) {
395
-						$newApps = $this->getAppsForCategory($singleCategory['id']);
396
-						foreach($allApps as $app) {
397
-							foreach($newApps as $key => $newApp) {
398
-								if($app['id'] === $newApp['id']) {
399
-									unset($newApps[$key]);
400
-								}
401
-							}
402
-						}
403
-						$allApps = array_merge($allApps, $newApps);
404
-					}
405
-
406
-					foreach($bundle->getAppIdentifiers() as $identifier) {
407
-						foreach($allApps as $app) {
408
-							if($app['id'] === $identifier) {
409
-								if($newCategory) {
410
-									$app['newCategory'] = true;
411
-									$app['categoryName'] = $bundle->getName();
412
-								}
413
-								$app['bundleId'] = $bundle->getIdentifier();
414
-								$newCategory = false;
415
-								$apps[] = $app;
416
-								continue;
417
-							}
418
-						}
419
-					}
420
-				}
421
-				break;
422
-			default:
423
-				$apps = $this->getAppsForCategory($category);
424
-
425
-				// sort by score
426
-				usort($apps, function ($a, $b) {
427
-					$a = (int)$a['score'];
428
-					$b = (int)$b['score'];
429
-					if ($a === $b) {
430
-						return 0;
431
-					}
432
-					return ($a > $b) ? -1 : 1;
433
-				});
434
-				break;
435
-		}
436
-
437
-		// fix groups to be an array
438
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n);
439
-		$apps = array_map(function($app) use ($dependencyAnalyzer) {
440
-
441
-			// fix groups
442
-			$groups = array();
443
-			if (is_string($app['groups'])) {
444
-				$groups = json_decode($app['groups']);
445
-			}
446
-			$app['groups'] = $groups;
447
-			$app['canUnInstall'] = !$app['active'] && $app['removable'];
448
-
449
-			// fix licence vs license
450
-			if (isset($app['license']) && !isset($app['licence'])) {
451
-				$app['licence'] = $app['license'];
452
-			}
453
-
454
-			// analyse dependencies
455
-			$missing = $dependencyAnalyzer->analyze($app);
456
-			$app['canInstall'] = empty($missing);
457
-			$app['missingDependencies'] = $missing;
458
-
459
-			$app['missingMinOwnCloudVersion'] = !isset($app['dependencies']['nextcloud']['@attributes']['min-version']);
460
-			$app['missingMaxOwnCloudVersion'] = !isset($app['dependencies']['nextcloud']['@attributes']['max-version']);
461
-
462
-			return $app;
463
-		}, $apps);
464
-
465
-		return new JSONResponse(['apps' => $apps, 'status' => 'success']);
466
-	}
56
+    const CAT_ENABLED = 0;
57
+    const CAT_DISABLED = 1;
58
+    const CAT_ALL_INSTALLED = 2;
59
+    const CAT_APP_BUNDLES = 3;
60
+    const CAT_UPDATES = 4;
61
+
62
+    /** @var \OCP\IL10N */
63
+    private $l10n;
64
+    /** @var IConfig */
65
+    private $config;
66
+    /** @var INavigationManager */
67
+    private $navigationManager;
68
+    /** @var IAppManager */
69
+    private $appManager;
70
+    /** @var CategoryFetcher */
71
+    private $categoryFetcher;
72
+    /** @var AppFetcher */
73
+    private $appFetcher;
74
+    /** @var IFactory */
75
+    private $l10nFactory;
76
+    /** @var BundleFetcher */
77
+    private $bundleFetcher;
78
+    /** @var Installer */
79
+    private $installer;
80
+
81
+    /**
82
+     * @param string $appName
83
+     * @param IRequest $request
84
+     * @param IL10N $l10n
85
+     * @param IConfig $config
86
+     * @param INavigationManager $navigationManager
87
+     * @param IAppManager $appManager
88
+     * @param CategoryFetcher $categoryFetcher
89
+     * @param AppFetcher $appFetcher
90
+     * @param IFactory $l10nFactory
91
+     * @param BundleFetcher $bundleFetcher
92
+     * @param Installer $installer
93
+     */
94
+    public function __construct($appName,
95
+                                IRequest $request,
96
+                                IL10N $l10n,
97
+                                IConfig $config,
98
+                                INavigationManager $navigationManager,
99
+                                IAppManager $appManager,
100
+                                CategoryFetcher $categoryFetcher,
101
+                                AppFetcher $appFetcher,
102
+                                IFactory $l10nFactory,
103
+                                BundleFetcher $bundleFetcher,
104
+                                Installer $installer) {
105
+        parent::__construct($appName, $request);
106
+        $this->l10n = $l10n;
107
+        $this->config = $config;
108
+        $this->navigationManager = $navigationManager;
109
+        $this->appManager = $appManager;
110
+        $this->categoryFetcher = $categoryFetcher;
111
+        $this->appFetcher = $appFetcher;
112
+        $this->l10nFactory = $l10nFactory;
113
+        $this->bundleFetcher = $bundleFetcher;
114
+        $this->installer = $installer;
115
+    }
116
+
117
+    /**
118
+     * @NoCSRFRequired
119
+     *
120
+     * @param string $category
121
+     * @return TemplateResponse
122
+     */
123
+    public function viewApps($category = '') {
124
+        if ($category === '') {
125
+            $category = 'installed';
126
+        }
127
+
128
+        $params = [];
129
+        $params['category'] = $category;
130
+        $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
131
+        $this->navigationManager->setActiveEntry('core_apps');
132
+
133
+        $templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user');
134
+        $policy = new ContentSecurityPolicy();
135
+        $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');
136
+        $templateResponse->setContentSecurityPolicy($policy);
137
+
138
+        return $templateResponse;
139
+    }
140
+
141
+    private function getAllCategories() {
142
+        $currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
143
+
144
+        $updateCount = count($this->getAppsWithUpdates());
145
+        $formattedCategories = [
146
+            ['id' => self::CAT_ALL_INSTALLED, 'ident' => 'installed', 'displayName' => (string)$this->l10n->t('Your apps')],
147
+            ['id' => self::CAT_UPDATES, 'ident' => 'updates', 'displayName' => (string)$this->l10n->t('Updates'), 'counter' => $updateCount],
148
+            ['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled apps')],
149
+            ['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Disabled apps')],
150
+            ['id' => self::CAT_APP_BUNDLES, 'ident' => 'app-bundles', 'displayName' => (string)$this->l10n->t('App bundles')],
151
+        ];
152
+        $categories = $this->categoryFetcher->get();
153
+        foreach($categories as $category) {
154
+            $formattedCategories[] = [
155
+                'id' => $category['id'],
156
+                'ident' => $category['id'],
157
+                'displayName' => isset($category['translations'][$currentLanguage]['name']) ? $category['translations'][$currentLanguage]['name'] : $category['translations']['en']['name'],
158
+            ];
159
+        }
160
+
161
+        return $formattedCategories;
162
+    }
163
+
164
+    /**
165
+     * Get all available categories
166
+     *
167
+     * @return JSONResponse
168
+     */
169
+    public function listCategories() {
170
+        return new JSONResponse($this->getAllCategories());
171
+    }
172
+
173
+    /**
174
+     * Get all apps for a category
175
+     *
176
+     * @param string $requestedCategory
177
+     * @return array
178
+     */
179
+    private function getAppsForCategory($requestedCategory) {
180
+        $versionParser = new VersionParser();
181
+        $formattedApps = [];
182
+        $apps = $this->appFetcher->get();
183
+        foreach($apps as $app) {
184
+            if (isset($app['isFeatured'])) {
185
+                $app['featured'] = $app['isFeatured'];
186
+            }
187
+
188
+            // Skip all apps not in the requested category
189
+            $isInCategory = false;
190
+            foreach($app['categories'] as $category) {
191
+                if($category === $requestedCategory) {
192
+                    $isInCategory = true;
193
+                }
194
+            }
195
+            if(!$isInCategory) {
196
+                continue;
197
+            }
198
+
199
+            $nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
200
+            $nextCloudVersionDependencies = [];
201
+            if($nextCloudVersion->getMinimumVersion() !== '') {
202
+                $nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
203
+            }
204
+            if($nextCloudVersion->getMaximumVersion() !== '') {
205
+                $nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
206
+            }
207
+            $phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
208
+            $existsLocally = \OC_App::getAppPath($app['id']) !== false;
209
+            $phpDependencies = [];
210
+            if($phpVersion->getMinimumVersion() !== '') {
211
+                $phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
212
+            }
213
+            if($phpVersion->getMaximumVersion() !== '') {
214
+                $phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
215
+            }
216
+            if(isset($app['releases'][0]['minIntSize'])) {
217
+                $phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
218
+            }
219
+            $authors = '';
220
+            foreach($app['authors'] as $key => $author) {
221
+                $authors .= $author['name'];
222
+                if($key !== count($app['authors']) - 1) {
223
+                    $authors .= ', ';
224
+                }
225
+            }
226
+
227
+            $currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
228
+            $enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
229
+            $groups = null;
230
+            if($enabledValue !== 'no' && $enabledValue !== 'yes') {
231
+                $groups = $enabledValue;
232
+            }
233
+
234
+            $currentVersion = '';
235
+            if($this->appManager->isInstalled($app['id'])) {
236
+                $currentVersion = \OC_App::getAppVersion($app['id']);
237
+            } else {
238
+                $currentLanguage = $app['releases'][0]['version'];
239
+            }
240
+
241
+            $formattedApps[] = [
242
+                'id' => $app['id'],
243
+                'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'],
244
+                'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'],
245
+                'license' => $app['releases'][0]['licenses'],
246
+                'author' => $authors,
247
+                'shipped' => false,
248
+                'version' => $currentVersion,
249
+                'default_enable' => '',
250
+                'types' => [],
251
+                'documentation' => [
252
+                    'admin' => $app['adminDocs'],
253
+                    'user' => $app['userDocs'],
254
+                    'developer' => $app['developerDocs']
255
+                ],
256
+                'website' => $app['website'],
257
+                'bugs' => $app['issueTracker'],
258
+                'detailpage' => $app['website'],
259
+                'dependencies' => array_merge(
260
+                    $nextCloudVersionDependencies,
261
+                    $phpDependencies
262
+                ),
263
+                'level' => ($app['featured'] === true) ? 200 : 100,
264
+                'missingMaxOwnCloudVersion' => false,
265
+                'missingMinOwnCloudVersion' => false,
266
+                'canInstall' => true,
267
+                'preview' => isset($app['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($app['screenshots'][0]['url']) : '',
268
+                'score' => $app['ratingOverall'],
269
+                'ratingNumOverall' => $app['ratingNumOverall'],
270
+                'ratingNumThresholdReached' => $app['ratingNumOverall'] > 5 ? true : false,
271
+                'removable' => $existsLocally,
272
+                'active' => $this->appManager->isEnabledForUser($app['id']),
273
+                'needsDownload' => !$existsLocally,
274
+                'groups' => $groups,
275
+                'fromAppStore' => true,
276
+            ];
277
+
278
+
279
+            $newVersion = $this->installer->isUpdateAvailable($app['id']);
280
+            if($newVersion && $this->appManager->isInstalled($app['id'])) {
281
+                $formattedApps[count($formattedApps)-1]['update'] = $newVersion;
282
+            }
283
+        }
284
+
285
+        return $formattedApps;
286
+    }
287
+
288
+    private function getAppsWithUpdates() {
289
+        $appClass = new \OC_App();
290
+        $apps = $appClass->listAllApps();
291
+        foreach($apps as $key => $app) {
292
+            $newVersion = $this->installer->isUpdateAvailable($app['id']);
293
+            if($newVersion !== false) {
294
+                $apps[$key]['update'] = $newVersion;
295
+            } else {
296
+                unset($apps[$key]);
297
+            }
298
+        }
299
+        usort($apps, function ($a, $b) {
300
+            $a = (string)$a['name'];
301
+            $b = (string)$b['name'];
302
+            if ($a === $b) {
303
+                return 0;
304
+            }
305
+            return ($a < $b) ? -1 : 1;
306
+        });
307
+        return $apps;
308
+    }
309
+
310
+    /**
311
+     * Get all available apps in a category
312
+     *
313
+     * @param string $category
314
+     * @return JSONResponse
315
+     */
316
+    public function listApps($category = '') {
317
+        $appClass = new \OC_App();
318
+
319
+        switch ($category) {
320
+            // installed apps
321
+            case 'installed':
322
+                $apps = $appClass->listAllApps();
323
+
324
+                foreach($apps as $key => $app) {
325
+                    $newVersion = $this->installer->isUpdateAvailable($app['id']);
326
+                    $apps[$key]['update'] = $newVersion;
327
+                }
328
+
329
+                usort($apps, function ($a, $b) {
330
+                    $a = (string)$a['name'];
331
+                    $b = (string)$b['name'];
332
+                    if ($a === $b) {
333
+                        return 0;
334
+                    }
335
+                    return ($a < $b) ? -1 : 1;
336
+                });
337
+                break;
338
+            // updates
339
+            case 'updates':
340
+                $apps = $this->getAppsWithUpdates();
341
+                break;
342
+            // enabled apps
343
+            case 'enabled':
344
+                $apps = $appClass->listAllApps();
345
+                $apps = array_filter($apps, function ($app) {
346
+                    return $app['active'];
347
+                });
348
+
349
+                foreach($apps as $key => $app) {
350
+                    $newVersion = $this->installer->isUpdateAvailable($app['id']);
351
+                    $apps[$key]['update'] = $newVersion;
352
+                }
353
+
354
+                usort($apps, function ($a, $b) {
355
+                    $a = (string)$a['name'];
356
+                    $b = (string)$b['name'];
357
+                    if ($a === $b) {
358
+                        return 0;
359
+                    }
360
+                    return ($a < $b) ? -1 : 1;
361
+                });
362
+                break;
363
+            // disabled  apps
364
+            case 'disabled':
365
+                $apps = $appClass->listAllApps();
366
+                $apps = array_filter($apps, function ($app) {
367
+                    return !$app['active'];
368
+                });
369
+
370
+                $apps = array_map(function ($app) {
371
+                    $newVersion = $this->installer->isUpdateAvailable($app['id']);
372
+                    if ($newVersion !== false) {
373
+                        $app['update'] = $newVersion;
374
+                    }
375
+                    return $app;
376
+                }, $apps);
377
+
378
+                usort($apps, function ($a, $b) {
379
+                    $a = (string)$a['name'];
380
+                    $b = (string)$b['name'];
381
+                    if ($a === $b) {
382
+                        return 0;
383
+                    }
384
+                    return ($a < $b) ? -1 : 1;
385
+                });
386
+                break;
387
+            case 'app-bundles':
388
+                $bundles = $this->bundleFetcher->getBundles();
389
+                $apps = [];
390
+                foreach($bundles as $bundle) {
391
+                    $newCategory = true;
392
+                    $allApps = $appClass->listAllApps();
393
+                    $categories = $this->getAllCategories();
394
+                    foreach($categories as $singleCategory) {
395
+                        $newApps = $this->getAppsForCategory($singleCategory['id']);
396
+                        foreach($allApps as $app) {
397
+                            foreach($newApps as $key => $newApp) {
398
+                                if($app['id'] === $newApp['id']) {
399
+                                    unset($newApps[$key]);
400
+                                }
401
+                            }
402
+                        }
403
+                        $allApps = array_merge($allApps, $newApps);
404
+                    }
405
+
406
+                    foreach($bundle->getAppIdentifiers() as $identifier) {
407
+                        foreach($allApps as $app) {
408
+                            if($app['id'] === $identifier) {
409
+                                if($newCategory) {
410
+                                    $app['newCategory'] = true;
411
+                                    $app['categoryName'] = $bundle->getName();
412
+                                }
413
+                                $app['bundleId'] = $bundle->getIdentifier();
414
+                                $newCategory = false;
415
+                                $apps[] = $app;
416
+                                continue;
417
+                            }
418
+                        }
419
+                    }
420
+                }
421
+                break;
422
+            default:
423
+                $apps = $this->getAppsForCategory($category);
424
+
425
+                // sort by score
426
+                usort($apps, function ($a, $b) {
427
+                    $a = (int)$a['score'];
428
+                    $b = (int)$b['score'];
429
+                    if ($a === $b) {
430
+                        return 0;
431
+                    }
432
+                    return ($a > $b) ? -1 : 1;
433
+                });
434
+                break;
435
+        }
436
+
437
+        // fix groups to be an array
438
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n);
439
+        $apps = array_map(function($app) use ($dependencyAnalyzer) {
440
+
441
+            // fix groups
442
+            $groups = array();
443
+            if (is_string($app['groups'])) {
444
+                $groups = json_decode($app['groups']);
445
+            }
446
+            $app['groups'] = $groups;
447
+            $app['canUnInstall'] = !$app['active'] && $app['removable'];
448
+
449
+            // fix licence vs license
450
+            if (isset($app['license']) && !isset($app['licence'])) {
451
+                $app['licence'] = $app['license'];
452
+            }
453
+
454
+            // analyse dependencies
455
+            $missing = $dependencyAnalyzer->analyze($app);
456
+            $app['canInstall'] = empty($missing);
457
+            $app['missingDependencies'] = $missing;
458
+
459
+            $app['missingMinOwnCloudVersion'] = !isset($app['dependencies']['nextcloud']['@attributes']['min-version']);
460
+            $app['missingMaxOwnCloudVersion'] = !isset($app['dependencies']['nextcloud']['@attributes']['max-version']);
461
+
462
+            return $app;
463
+        }, $apps);
464
+
465
+        return new JSONResponse(['apps' => $apps, 'status' => 'success']);
466
+    }
467 467
 }
Please login to merge, or discard this patch.
Spacing   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -143,14 +143,14 @@  discard block
 block discarded – undo
143 143
 
144 144
 		$updateCount = count($this->getAppsWithUpdates());
145 145
 		$formattedCategories = [
146
-			['id' => self::CAT_ALL_INSTALLED, 'ident' => 'installed', 'displayName' => (string)$this->l10n->t('Your apps')],
147
-			['id' => self::CAT_UPDATES, 'ident' => 'updates', 'displayName' => (string)$this->l10n->t('Updates'), 'counter' => $updateCount],
148
-			['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled apps')],
149
-			['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Disabled apps')],
150
-			['id' => self::CAT_APP_BUNDLES, 'ident' => 'app-bundles', 'displayName' => (string)$this->l10n->t('App bundles')],
146
+			['id' => self::CAT_ALL_INSTALLED, 'ident' => 'installed', 'displayName' => (string) $this->l10n->t('Your apps')],
147
+			['id' => self::CAT_UPDATES, 'ident' => 'updates', 'displayName' => (string) $this->l10n->t('Updates'), 'counter' => $updateCount],
148
+			['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string) $this->l10n->t('Enabled apps')],
149
+			['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string) $this->l10n->t('Disabled apps')],
150
+			['id' => self::CAT_APP_BUNDLES, 'ident' => 'app-bundles', 'displayName' => (string) $this->l10n->t('App bundles')],
151 151
 		];
152 152
 		$categories = $this->categoryFetcher->get();
153
-		foreach($categories as $category) {
153
+		foreach ($categories as $category) {
154 154
 			$formattedCategories[] = [
155 155
 				'id' => $category['id'],
156 156
 				'ident' => $category['id'],
@@ -180,46 +180,46 @@  discard block
 block discarded – undo
180 180
 		$versionParser = new VersionParser();
181 181
 		$formattedApps = [];
182 182
 		$apps = $this->appFetcher->get();
183
-		foreach($apps as $app) {
183
+		foreach ($apps as $app) {
184 184
 			if (isset($app['isFeatured'])) {
185 185
 				$app['featured'] = $app['isFeatured'];
186 186
 			}
187 187
 
188 188
 			// Skip all apps not in the requested category
189 189
 			$isInCategory = false;
190
-			foreach($app['categories'] as $category) {
191
-				if($category === $requestedCategory) {
190
+			foreach ($app['categories'] as $category) {
191
+				if ($category === $requestedCategory) {
192 192
 					$isInCategory = true;
193 193
 				}
194 194
 			}
195
-			if(!$isInCategory) {
195
+			if (!$isInCategory) {
196 196
 				continue;
197 197
 			}
198 198
 
199 199
 			$nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
200 200
 			$nextCloudVersionDependencies = [];
201
-			if($nextCloudVersion->getMinimumVersion() !== '') {
201
+			if ($nextCloudVersion->getMinimumVersion() !== '') {
202 202
 				$nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
203 203
 			}
204
-			if($nextCloudVersion->getMaximumVersion() !== '') {
204
+			if ($nextCloudVersion->getMaximumVersion() !== '') {
205 205
 				$nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
206 206
 			}
207 207
 			$phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
208 208
 			$existsLocally = \OC_App::getAppPath($app['id']) !== false;
209 209
 			$phpDependencies = [];
210
-			if($phpVersion->getMinimumVersion() !== '') {
210
+			if ($phpVersion->getMinimumVersion() !== '') {
211 211
 				$phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
212 212
 			}
213
-			if($phpVersion->getMaximumVersion() !== '') {
213
+			if ($phpVersion->getMaximumVersion() !== '') {
214 214
 				$phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
215 215
 			}
216
-			if(isset($app['releases'][0]['minIntSize'])) {
216
+			if (isset($app['releases'][0]['minIntSize'])) {
217 217
 				$phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
218 218
 			}
219 219
 			$authors = '';
220
-			foreach($app['authors'] as $key => $author) {
220
+			foreach ($app['authors'] as $key => $author) {
221 221
 				$authors .= $author['name'];
222
-				if($key !== count($app['authors']) - 1) {
222
+				if ($key !== count($app['authors']) - 1) {
223 223
 					$authors .= ', ';
224 224
 				}
225 225
 			}
@@ -227,12 +227,12 @@  discard block
 block discarded – undo
227 227
 			$currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
228 228
 			$enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
229 229
 			$groups = null;
230
-			if($enabledValue !== 'no' && $enabledValue !== 'yes') {
230
+			if ($enabledValue !== 'no' && $enabledValue !== 'yes') {
231 231
 				$groups = $enabledValue;
232 232
 			}
233 233
 
234 234
 			$currentVersion = '';
235
-			if($this->appManager->isInstalled($app['id'])) {
235
+			if ($this->appManager->isInstalled($app['id'])) {
236 236
 				$currentVersion = \OC_App::getAppVersion($app['id']);
237 237
 			} else {
238 238
 				$currentLanguage = $app['releases'][0]['version'];
@@ -277,8 +277,8 @@  discard block
 block discarded – undo
277 277
 
278 278
 
279 279
 			$newVersion = $this->installer->isUpdateAvailable($app['id']);
280
-			if($newVersion && $this->appManager->isInstalled($app['id'])) {
281
-				$formattedApps[count($formattedApps)-1]['update'] = $newVersion;
280
+			if ($newVersion && $this->appManager->isInstalled($app['id'])) {
281
+				$formattedApps[count($formattedApps) - 1]['update'] = $newVersion;
282 282
 			}
283 283
 		}
284 284
 
@@ -288,17 +288,17 @@  discard block
 block discarded – undo
288 288
 	private function getAppsWithUpdates() {
289 289
 		$appClass = new \OC_App();
290 290
 		$apps = $appClass->listAllApps();
291
-		foreach($apps as $key => $app) {
291
+		foreach ($apps as $key => $app) {
292 292
 			$newVersion = $this->installer->isUpdateAvailable($app['id']);
293
-			if($newVersion !== false) {
293
+			if ($newVersion !== false) {
294 294
 				$apps[$key]['update'] = $newVersion;
295 295
 			} else {
296 296
 				unset($apps[$key]);
297 297
 			}
298 298
 		}
299
-		usort($apps, function ($a, $b) {
300
-			$a = (string)$a['name'];
301
-			$b = (string)$b['name'];
299
+		usort($apps, function($a, $b) {
300
+			$a = (string) $a['name'];
301
+			$b = (string) $b['name'];
302 302
 			if ($a === $b) {
303 303
 				return 0;
304 304
 			}
@@ -321,14 +321,14 @@  discard block
 block discarded – undo
321 321
 			case 'installed':
322 322
 				$apps = $appClass->listAllApps();
323 323
 
324
-				foreach($apps as $key => $app) {
324
+				foreach ($apps as $key => $app) {
325 325
 					$newVersion = $this->installer->isUpdateAvailable($app['id']);
326 326
 					$apps[$key]['update'] = $newVersion;
327 327
 				}
328 328
 
329
-				usort($apps, function ($a, $b) {
330
-					$a = (string)$a['name'];
331
-					$b = (string)$b['name'];
329
+				usort($apps, function($a, $b) {
330
+					$a = (string) $a['name'];
331
+					$b = (string) $b['name'];
332 332
 					if ($a === $b) {
333 333
 						return 0;
334 334
 					}
@@ -342,18 +342,18 @@  discard block
 block discarded – undo
342 342
 			// enabled apps
343 343
 			case 'enabled':
344 344
 				$apps = $appClass->listAllApps();
345
-				$apps = array_filter($apps, function ($app) {
345
+				$apps = array_filter($apps, function($app) {
346 346
 					return $app['active'];
347 347
 				});
348 348
 
349
-				foreach($apps as $key => $app) {
349
+				foreach ($apps as $key => $app) {
350 350
 					$newVersion = $this->installer->isUpdateAvailable($app['id']);
351 351
 					$apps[$key]['update'] = $newVersion;
352 352
 				}
353 353
 
354
-				usort($apps, function ($a, $b) {
355
-					$a = (string)$a['name'];
356
-					$b = (string)$b['name'];
354
+				usort($apps, function($a, $b) {
355
+					$a = (string) $a['name'];
356
+					$b = (string) $b['name'];
357 357
 					if ($a === $b) {
358 358
 						return 0;
359 359
 					}
@@ -363,11 +363,11 @@  discard block
 block discarded – undo
363 363
 			// disabled  apps
364 364
 			case 'disabled':
365 365
 				$apps = $appClass->listAllApps();
366
-				$apps = array_filter($apps, function ($app) {
366
+				$apps = array_filter($apps, function($app) {
367 367
 					return !$app['active'];
368 368
 				});
369 369
 
370
-				$apps = array_map(function ($app) {
370
+				$apps = array_map(function($app) {
371 371
 					$newVersion = $this->installer->isUpdateAvailable($app['id']);
372 372
 					if ($newVersion !== false) {
373 373
 						$app['update'] = $newVersion;
@@ -375,9 +375,9 @@  discard block
 block discarded – undo
375 375
 					return $app;
376 376
 				}, $apps);
377 377
 
378
-				usort($apps, function ($a, $b) {
379
-					$a = (string)$a['name'];
380
-					$b = (string)$b['name'];
378
+				usort($apps, function($a, $b) {
379
+					$a = (string) $a['name'];
380
+					$b = (string) $b['name'];
381 381
 					if ($a === $b) {
382 382
 						return 0;
383 383
 					}
@@ -387,15 +387,15 @@  discard block
 block discarded – undo
387 387
 			case 'app-bundles':
388 388
 				$bundles = $this->bundleFetcher->getBundles();
389 389
 				$apps = [];
390
-				foreach($bundles as $bundle) {
390
+				foreach ($bundles as $bundle) {
391 391
 					$newCategory = true;
392 392
 					$allApps = $appClass->listAllApps();
393 393
 					$categories = $this->getAllCategories();
394
-					foreach($categories as $singleCategory) {
394
+					foreach ($categories as $singleCategory) {
395 395
 						$newApps = $this->getAppsForCategory($singleCategory['id']);
396
-						foreach($allApps as $app) {
397
-							foreach($newApps as $key => $newApp) {
398
-								if($app['id'] === $newApp['id']) {
396
+						foreach ($allApps as $app) {
397
+							foreach ($newApps as $key => $newApp) {
398
+								if ($app['id'] === $newApp['id']) {
399 399
 									unset($newApps[$key]);
400 400
 								}
401 401
 							}
@@ -403,10 +403,10 @@  discard block
 block discarded – undo
403 403
 						$allApps = array_merge($allApps, $newApps);
404 404
 					}
405 405
 
406
-					foreach($bundle->getAppIdentifiers() as $identifier) {
407
-						foreach($allApps as $app) {
408
-							if($app['id'] === $identifier) {
409
-								if($newCategory) {
406
+					foreach ($bundle->getAppIdentifiers() as $identifier) {
407
+						foreach ($allApps as $app) {
408
+							if ($app['id'] === $identifier) {
409
+								if ($newCategory) {
410 410
 									$app['newCategory'] = true;
411 411
 									$app['categoryName'] = $bundle->getName();
412 412
 								}
@@ -423,9 +423,9 @@  discard block
 block discarded – undo
423 423
 				$apps = $this->getAppsForCategory($category);
424 424
 
425 425
 				// sort by score
426
-				usort($apps, function ($a, $b) {
427
-					$a = (int)$a['score'];
428
-					$b = (int)$b['score'];
426
+				usort($apps, function($a, $b) {
427
+					$a = (int) $a['score'];
428
+					$b = (int) $b['score'];
429 429
 					if ($a === $b) {
430 430
 						return 0;
431 431
 					}
Please login to merge, or discard this patch.
apps/user_ldap/lib/Jobs/CleanUp.php 1 patch
Indentation   +192 added lines, -192 removed lines patch added patch discarded remove patch
@@ -43,197 +43,197 @@
 block discarded – undo
43 43
  * @package OCA\User_LDAP\Jobs;
44 44
  */
45 45
 class CleanUp extends TimedJob {
46
-	/** @var int $limit amount of users that should be checked per run */
47
-	protected $limit = 50;
48
-
49
-	/** @var int $defaultIntervalMin default interval in minutes */
50
-	protected $defaultIntervalMin = 51;
51
-
52
-	/** @var User_LDAP|User_Proxy $userBackend */
53
-	protected $userBackend;
54
-
55
-	/** @var \OCP\IConfig $ocConfig */
56
-	protected $ocConfig;
57
-
58
-	/** @var \OCP\IDBConnection $db */
59
-	protected $db;
60
-
61
-	/** @var Helper $ldapHelper */
62
-	protected $ldapHelper;
63
-
64
-	/** @var \OCA\User_LDAP\Mapping\UserMapping */
65
-	protected $mapping;
66
-
67
-	/** @var \OCA\User_LDAP\User\DeletedUsersIndex */
68
-	protected $dui;
69
-
70
-	public function __construct() {
71
-		$minutes = \OC::$server->getConfig()->getSystemValue(
72
-			'ldapUserCleanupInterval', (string)$this->defaultIntervalMin);
73
-		$this->setInterval((int)$minutes * 60);
74
-	}
75
-
76
-	/**
77
-	 * assigns the instances passed to run() to the class properties
78
-	 * @param array $arguments
79
-	 */
80
-	public function setArguments($arguments) {
81
-		//Dependency Injection is not possible, because the constructor will
82
-		//only get values that are serialized to JSON. I.e. whatever we would
83
-		//pass in app.php we do add here, except something else is passed e.g.
84
-		//in tests.
85
-
86
-		if(isset($arguments['helper'])) {
87
-			$this->ldapHelper = $arguments['helper'];
88
-		} else {
89
-			$this->ldapHelper = new Helper(\OC::$server->getConfig());
90
-		}
91
-
92
-		if(isset($arguments['ocConfig'])) {
93
-			$this->ocConfig = $arguments['ocConfig'];
94
-		} else {
95
-			$this->ocConfig = \OC::$server->getConfig();
96
-		}
97
-
98
-		if(isset($arguments['userBackend'])) {
99
-			$this->userBackend = $arguments['userBackend'];
100
-		} else {
101
-			$this->userBackend =  new User_Proxy(
102
-				$this->ldapHelper->getServerConfigurationPrefixes(true),
103
-				new LDAP(),
104
-				$this->ocConfig,
105
-				\OC::$server->getNotificationManager(),
106
-				\OC::$server->getUserSession(),
107
-				\OC::$server->query('LDAPUserPluginManager')
108
-			);
109
-		}
110
-
111
-		if(isset($arguments['db'])) {
112
-			$this->db = $arguments['db'];
113
-		} else {
114
-			$this->db = \OC::$server->getDatabaseConnection();
115
-		}
116
-
117
-		if(isset($arguments['mapping'])) {
118
-			$this->mapping = $arguments['mapping'];
119
-		} else {
120
-			$this->mapping = new UserMapping($this->db);
121
-		}
122
-
123
-		if(isset($arguments['deletedUsersIndex'])) {
124
-			$this->dui = $arguments['deletedUsersIndex'];
125
-		} else {
126
-			$this->dui = new DeletedUsersIndex(
127
-				$this->ocConfig, $this->db, $this->mapping);
128
-		}
129
-	}
130
-
131
-	/**
132
-	 * makes the background job do its work
133
-	 * @param array $argument
134
-	 */
135
-	public function run($argument) {
136
-		$this->setArguments($argument);
137
-
138
-		if(!$this->isCleanUpAllowed()) {
139
-			return;
140
-		}
141
-		$users = $this->mapping->getList($this->getOffset(), $this->limit);
142
-		if(!is_array($users)) {
143
-			//something wrong? Let's start from the beginning next time and
144
-			//abort
145
-			$this->setOffset(true);
146
-			return;
147
-		}
148
-		$resetOffset = $this->isOffsetResetNecessary(count($users));
149
-		$this->checkUsers($users);
150
-		$this->setOffset($resetOffset);
151
-	}
152
-
153
-	/**
154
-	 * checks whether next run should start at 0 again
155
-	 * @param int $resultCount
156
-	 * @return bool
157
-	 */
158
-	public function isOffsetResetNecessary($resultCount) {
159
-		return $resultCount < $this->limit;
160
-	}
161
-
162
-	/**
163
-	 * checks whether cleaning up LDAP users is allowed
164
-	 * @return bool
165
-	 */
166
-	public function isCleanUpAllowed() {
167
-		try {
168
-			if($this->ldapHelper->haveDisabledConfigurations()) {
169
-				return false;
170
-			}
171
-		} catch (\Exception $e) {
172
-			return false;
173
-		}
174
-
175
-		$enabled = $this->isCleanUpEnabled();
176
-
177
-		return $enabled;
178
-	}
179
-
180
-	/**
181
-	 * checks whether clean up is enabled by configuration
182
-	 * @return bool
183
-	 */
184
-	private function isCleanUpEnabled() {
185
-		return (bool)$this->ocConfig->getSystemValue(
186
-			'ldapUserCleanupInterval', (string)$this->defaultIntervalMin);
187
-	}
188
-
189
-	/**
190
-	 * checks users whether they are still existing
191
-	 * @param array $users result from getMappedUsers()
192
-	 */
193
-	private function checkUsers(array $users) {
194
-		foreach($users as $user) {
195
-			$this->checkUser($user);
196
-		}
197
-	}
198
-
199
-	/**
200
-	 * checks whether a user is still existing in LDAP
201
-	 * @param string[] $user
202
-	 */
203
-	private function checkUser(array $user) {
204
-		if($this->userBackend->userExistsOnLDAP($user['name'])) {
205
-			//still available, all good
206
-
207
-			return;
208
-		}
209
-
210
-		$this->dui->markUser($user['name']);
211
-	}
212
-
213
-	/**
214
-	 * gets the offset to fetch users from the mappings table
215
-	 * @return int
216
-	 */
217
-	private function getOffset() {
218
-		return (int)$this->ocConfig->getAppValue('user_ldap', 'cleanUpJobOffset', 0);
219
-	}
220
-
221
-	/**
222
-	 * sets the new offset for the next run
223
-	 * @param bool $reset whether the offset should be set to 0
224
-	 */
225
-	public function setOffset($reset = false) {
226
-		$newOffset = $reset ? 0 :
227
-			$this->getOffset() + $this->limit;
228
-		$this->ocConfig->setAppValue('user_ldap', 'cleanUpJobOffset', $newOffset);
229
-	}
230
-
231
-	/**
232
-	 * returns the chunk size (limit in DB speak)
233
-	 * @return int
234
-	 */
235
-	public function getChunkSize() {
236
-		return $this->limit;
237
-	}
46
+    /** @var int $limit amount of users that should be checked per run */
47
+    protected $limit = 50;
48
+
49
+    /** @var int $defaultIntervalMin default interval in minutes */
50
+    protected $defaultIntervalMin = 51;
51
+
52
+    /** @var User_LDAP|User_Proxy $userBackend */
53
+    protected $userBackend;
54
+
55
+    /** @var \OCP\IConfig $ocConfig */
56
+    protected $ocConfig;
57
+
58
+    /** @var \OCP\IDBConnection $db */
59
+    protected $db;
60
+
61
+    /** @var Helper $ldapHelper */
62
+    protected $ldapHelper;
63
+
64
+    /** @var \OCA\User_LDAP\Mapping\UserMapping */
65
+    protected $mapping;
66
+
67
+    /** @var \OCA\User_LDAP\User\DeletedUsersIndex */
68
+    protected $dui;
69
+
70
+    public function __construct() {
71
+        $minutes = \OC::$server->getConfig()->getSystemValue(
72
+            'ldapUserCleanupInterval', (string)$this->defaultIntervalMin);
73
+        $this->setInterval((int)$minutes * 60);
74
+    }
75
+
76
+    /**
77
+     * assigns the instances passed to run() to the class properties
78
+     * @param array $arguments
79
+     */
80
+    public function setArguments($arguments) {
81
+        //Dependency Injection is not possible, because the constructor will
82
+        //only get values that are serialized to JSON. I.e. whatever we would
83
+        //pass in app.php we do add here, except something else is passed e.g.
84
+        //in tests.
85
+
86
+        if(isset($arguments['helper'])) {
87
+            $this->ldapHelper = $arguments['helper'];
88
+        } else {
89
+            $this->ldapHelper = new Helper(\OC::$server->getConfig());
90
+        }
91
+
92
+        if(isset($arguments['ocConfig'])) {
93
+            $this->ocConfig = $arguments['ocConfig'];
94
+        } else {
95
+            $this->ocConfig = \OC::$server->getConfig();
96
+        }
97
+
98
+        if(isset($arguments['userBackend'])) {
99
+            $this->userBackend = $arguments['userBackend'];
100
+        } else {
101
+            $this->userBackend =  new User_Proxy(
102
+                $this->ldapHelper->getServerConfigurationPrefixes(true),
103
+                new LDAP(),
104
+                $this->ocConfig,
105
+                \OC::$server->getNotificationManager(),
106
+                \OC::$server->getUserSession(),
107
+                \OC::$server->query('LDAPUserPluginManager')
108
+            );
109
+        }
110
+
111
+        if(isset($arguments['db'])) {
112
+            $this->db = $arguments['db'];
113
+        } else {
114
+            $this->db = \OC::$server->getDatabaseConnection();
115
+        }
116
+
117
+        if(isset($arguments['mapping'])) {
118
+            $this->mapping = $arguments['mapping'];
119
+        } else {
120
+            $this->mapping = new UserMapping($this->db);
121
+        }
122
+
123
+        if(isset($arguments['deletedUsersIndex'])) {
124
+            $this->dui = $arguments['deletedUsersIndex'];
125
+        } else {
126
+            $this->dui = new DeletedUsersIndex(
127
+                $this->ocConfig, $this->db, $this->mapping);
128
+        }
129
+    }
130
+
131
+    /**
132
+     * makes the background job do its work
133
+     * @param array $argument
134
+     */
135
+    public function run($argument) {
136
+        $this->setArguments($argument);
137
+
138
+        if(!$this->isCleanUpAllowed()) {
139
+            return;
140
+        }
141
+        $users = $this->mapping->getList($this->getOffset(), $this->limit);
142
+        if(!is_array($users)) {
143
+            //something wrong? Let's start from the beginning next time and
144
+            //abort
145
+            $this->setOffset(true);
146
+            return;
147
+        }
148
+        $resetOffset = $this->isOffsetResetNecessary(count($users));
149
+        $this->checkUsers($users);
150
+        $this->setOffset($resetOffset);
151
+    }
152
+
153
+    /**
154
+     * checks whether next run should start at 0 again
155
+     * @param int $resultCount
156
+     * @return bool
157
+     */
158
+    public function isOffsetResetNecessary($resultCount) {
159
+        return $resultCount < $this->limit;
160
+    }
161
+
162
+    /**
163
+     * checks whether cleaning up LDAP users is allowed
164
+     * @return bool
165
+     */
166
+    public function isCleanUpAllowed() {
167
+        try {
168
+            if($this->ldapHelper->haveDisabledConfigurations()) {
169
+                return false;
170
+            }
171
+        } catch (\Exception $e) {
172
+            return false;
173
+        }
174
+
175
+        $enabled = $this->isCleanUpEnabled();
176
+
177
+        return $enabled;
178
+    }
179
+
180
+    /**
181
+     * checks whether clean up is enabled by configuration
182
+     * @return bool
183
+     */
184
+    private function isCleanUpEnabled() {
185
+        return (bool)$this->ocConfig->getSystemValue(
186
+            'ldapUserCleanupInterval', (string)$this->defaultIntervalMin);
187
+    }
188
+
189
+    /**
190
+     * checks users whether they are still existing
191
+     * @param array $users result from getMappedUsers()
192
+     */
193
+    private function checkUsers(array $users) {
194
+        foreach($users as $user) {
195
+            $this->checkUser($user);
196
+        }
197
+    }
198
+
199
+    /**
200
+     * checks whether a user is still existing in LDAP
201
+     * @param string[] $user
202
+     */
203
+    private function checkUser(array $user) {
204
+        if($this->userBackend->userExistsOnLDAP($user['name'])) {
205
+            //still available, all good
206
+
207
+            return;
208
+        }
209
+
210
+        $this->dui->markUser($user['name']);
211
+    }
212
+
213
+    /**
214
+     * gets the offset to fetch users from the mappings table
215
+     * @return int
216
+     */
217
+    private function getOffset() {
218
+        return (int)$this->ocConfig->getAppValue('user_ldap', 'cleanUpJobOffset', 0);
219
+    }
220
+
221
+    /**
222
+     * sets the new offset for the next run
223
+     * @param bool $reset whether the offset should be set to 0
224
+     */
225
+    public function setOffset($reset = false) {
226
+        $newOffset = $reset ? 0 :
227
+            $this->getOffset() + $this->limit;
228
+        $this->ocConfig->setAppValue('user_ldap', 'cleanUpJobOffset', $newOffset);
229
+    }
230
+
231
+    /**
232
+     * returns the chunk size (limit in DB speak)
233
+     * @return int
234
+     */
235
+    public function getChunkSize() {
236
+        return $this->limit;
237
+    }
238 238
 
239 239
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareController.php 1 patch
Indentation   +564 added lines, -564 removed lines patch added patch discarded remove patch
@@ -67,572 +67,572 @@
 block discarded – undo
67 67
  */
68 68
 class ShareController extends Controller {
69 69
 
70
-	/** @var IConfig */
71
-	protected $config;
72
-	/** @var IURLGenerator */
73
-	protected $urlGenerator;
74
-	/** @var IUserManager */
75
-	protected $userManager;
76
-	/** @var ILogger */
77
-	protected $logger;
78
-	/** @var \OCP\Activity\IManager */
79
-	protected $activityManager;
80
-	/** @var \OCP\Share\IManager */
81
-	protected $shareManager;
82
-	/** @var ISession */
83
-	protected $session;
84
-	/** @var IPreview */
85
-	protected $previewManager;
86
-	/** @var IRootFolder */
87
-	protected $rootFolder;
88
-	/** @var FederatedShareProvider */
89
-	protected $federatedShareProvider;
90
-	/** @var EventDispatcherInterface */
91
-	protected $eventDispatcher;
92
-	/** @var IL10N */
93
-	protected $l10n;
94
-	/** @var Defaults */
95
-	protected $defaults;
96
-
97
-	/**
98
-	 * @param string $appName
99
-	 * @param IRequest $request
100
-	 * @param IConfig $config
101
-	 * @param IURLGenerator $urlGenerator
102
-	 * @param IUserManager $userManager
103
-	 * @param ILogger $logger
104
-	 * @param \OCP\Activity\IManager $activityManager
105
-	 * @param \OCP\Share\IManager $shareManager
106
-	 * @param ISession $session
107
-	 * @param IPreview $previewManager
108
-	 * @param IRootFolder $rootFolder
109
-	 * @param FederatedShareProvider $federatedShareProvider
110
-	 * @param EventDispatcherInterface $eventDispatcher
111
-	 * @param IL10N $l10n
112
-	 * @param Defaults $defaults
113
-	 */
114
-	public function __construct($appName,
115
-								IRequest $request,
116
-								IConfig $config,
117
-								IURLGenerator $urlGenerator,
118
-								IUserManager $userManager,
119
-								ILogger $logger,
120
-								\OCP\Activity\IManager $activityManager,
121
-								\OCP\Share\IManager $shareManager,
122
-								ISession $session,
123
-								IPreview $previewManager,
124
-								IRootFolder $rootFolder,
125
-								FederatedShareProvider $federatedShareProvider,
126
-								EventDispatcherInterface $eventDispatcher,
127
-								IL10N $l10n,
128
-								Defaults $defaults) {
129
-		parent::__construct($appName, $request);
130
-
131
-		$this->config = $config;
132
-		$this->urlGenerator = $urlGenerator;
133
-		$this->userManager = $userManager;
134
-		$this->logger = $logger;
135
-		$this->activityManager = $activityManager;
136
-		$this->shareManager = $shareManager;
137
-		$this->session = $session;
138
-		$this->previewManager = $previewManager;
139
-		$this->rootFolder = $rootFolder;
140
-		$this->federatedShareProvider = $federatedShareProvider;
141
-		$this->eventDispatcher = $eventDispatcher;
142
-		$this->l10n = $l10n;
143
-		$this->defaults = $defaults;
144
-	}
145
-
146
-	/**
147
-	 * @PublicPage
148
-	 * @NoCSRFRequired
149
-	 *
150
-	 * @param string $token
151
-	 * @return TemplateResponse|RedirectResponse
152
-	 */
153
-	public function showAuthenticate($token) {
154
-		$share = $this->shareManager->getShareByToken($token);
155
-
156
-		if($this->linkShareAuth($share)) {
157
-			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
158
-		}
159
-
160
-		return new TemplateResponse($this->appName, 'authenticate', array(), 'guest');
161
-	}
162
-
163
-	/**
164
-	 * @PublicPage
165
-	 * @UseSession
166
-	 * @BruteForceProtection(action=publicLinkAuth)
167
-	 *
168
-	 * Authenticates against password-protected shares
169
-	 * @param string $token
170
-	 * @param string $password
171
-	 * @return RedirectResponse|TemplateResponse|NotFoundResponse
172
-	 */
173
-	public function authenticate($token, $password = '') {
174
-
175
-		// Check whether share exists
176
-		try {
177
-			$share = $this->shareManager->getShareByToken($token);
178
-		} catch (ShareNotFound $e) {
179
-			return new NotFoundResponse();
180
-		}
181
-
182
-		$authenticate = $this->linkShareAuth($share, $password);
183
-
184
-		if($authenticate === true) {
185
-			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
186
-		}
187
-
188
-		$response = new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest');
189
-		$response->throttle();
190
-		return $response;
191
-	}
192
-
193
-	/**
194
-	 * Authenticate a link item with the given password.
195
-	 * Or use the session if no password is provided.
196
-	 *
197
-	 * This is a modified version of Helper::authenticate
198
-	 * TODO: Try to merge back eventually with Helper::authenticate
199
-	 *
200
-	 * @param \OCP\Share\IShare $share
201
-	 * @param string|null $password
202
-	 * @return bool
203
-	 */
204
-	private function linkShareAuth(\OCP\Share\IShare $share, $password = null) {
205
-		if ($password !== null) {
206
-			if ($this->shareManager->checkPassword($share, $password)) {
207
-				$this->session->set('public_link_authenticated', (string)$share->getId());
208
-			} else {
209
-				$this->emitAccessShareHook($share, 403, 'Wrong password');
210
-				return false;
211
-			}
212
-		} else {
213
-			// not authenticated ?
214
-			if ( ! $this->session->exists('public_link_authenticated')
215
-				|| $this->session->get('public_link_authenticated') !== (string)$share->getId()) {
216
-				return false;
217
-			}
218
-		}
219
-		return true;
220
-	}
221
-
222
-	/**
223
-	 * throws hooks when a share is attempted to be accessed
224
-	 *
225
-	 * @param \OCP\Share\IShare|string $share the Share instance if available,
226
-	 * otherwise token
227
-	 * @param int $errorCode
228
-	 * @param string $errorMessage
229
-	 * @throws \OC\HintException
230
-	 * @throws \OC\ServerNotAvailableException
231
-	 */
232
-	protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') {
233
-		$itemType = $itemSource = $uidOwner = '';
234
-		$token = $share;
235
-		$exception = null;
236
-		if($share instanceof \OCP\Share\IShare) {
237
-			try {
238
-				$token = $share->getToken();
239
-				$uidOwner = $share->getSharedBy();
240
-				$itemType = $share->getNodeType();
241
-				$itemSource = $share->getNodeId();
242
-			} catch (\Exception $e) {
243
-				// we log what we know and pass on the exception afterwards
244
-				$exception = $e;
245
-			}
246
-		}
247
-		\OC_Hook::emit('OCP\Share', 'share_link_access', [
248
-			'itemType' => $itemType,
249
-			'itemSource' => $itemSource,
250
-			'uidOwner' => $uidOwner,
251
-			'token' => $token,
252
-			'errorCode' => $errorCode,
253
-			'errorMessage' => $errorMessage,
254
-		]);
255
-		if(!is_null($exception)) {
256
-			throw $exception;
257
-		}
258
-	}
259
-
260
-	/**
261
-	 * Validate the permissions of the share
262
-	 *
263
-	 * @param Share\IShare $share
264
-	 * @return bool
265
-	 */
266
-	private function validateShare(\OCP\Share\IShare $share) {
267
-		return $share->getNode()->isReadable() && $share->getNode()->isShareable();
268
-	}
269
-
270
-	/**
271
-	 * @PublicPage
272
-	 * @NoCSRFRequired
273
-	 *
274
-	 * @param string $token
275
-	 * @param string $path
276
-	 * @return TemplateResponse|RedirectResponse|NotFoundResponse
277
-	 * @throws NotFoundException
278
-	 * @throws \Exception
279
-	 */
280
-	public function showShare($token, $path = '') {
281
-		\OC_User::setIncognitoMode(true);
282
-
283
-		// Check whether share exists
284
-		try {
285
-			$share = $this->shareManager->getShareByToken($token);
286
-		} catch (ShareNotFound $e) {
287
-			$this->emitAccessShareHook($token, 404, 'Share not found');
288
-			return new NotFoundResponse();
289
-		}
290
-
291
-		// Share is password protected - check whether the user is permitted to access the share
292
-		if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
293
-			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
294
-				array('token' => $token)));
295
-		}
296
-
297
-		if (!$this->validateShare($share)) {
298
-			throw new NotFoundException();
299
-		}
300
-		// We can't get the path of a file share
301
-		try {
302
-			if ($share->getNode() instanceof \OCP\Files\File && $path !== '') {
303
-				$this->emitAccessShareHook($share, 404, 'Share not found');
304
-				throw new NotFoundException();
305
-			}
306
-		} catch (\Exception $e) {
307
-			$this->emitAccessShareHook($share, 404, 'Share not found');
308
-			throw $e;
309
-		}
310
-
311
-		$shareTmpl = [];
312
-		$shareTmpl['displayName'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
313
-		$shareTmpl['owner'] = $share->getShareOwner();
314
-		$shareTmpl['filename'] = $share->getNode()->getName();
315
-		$shareTmpl['directory_path'] = $share->getTarget();
316
-		$shareTmpl['mimetype'] = $share->getNode()->getMimetype();
317
-		$shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype());
318
-		$shareTmpl['dirToken'] = $token;
319
-		$shareTmpl['sharingToken'] = $token;
320
-		$shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
321
-		$shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
322
-		$shareTmpl['dir'] = '';
323
-		$shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize();
324
-		$shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize());
325
-
326
-		// Show file list
327
-		$hideFileList = false;
328
-		if ($share->getNode() instanceof \OCP\Files\Folder) {
329
-			/** @var \OCP\Files\Folder $rootFolder */
330
-			$rootFolder = $share->getNode();
331
-
332
-			try {
333
-				$folderNode = $rootFolder->get($path);
334
-			} catch (\OCP\Files\NotFoundException $e) {
335
-				$this->emitAccessShareHook($share, 404, 'Share not found');
336
-				throw new NotFoundException();
337
-			}
338
-
339
-			$shareTmpl['dir'] = $rootFolder->getRelativePath($folderNode->getPath());
340
-
341
-			/*
70
+    /** @var IConfig */
71
+    protected $config;
72
+    /** @var IURLGenerator */
73
+    protected $urlGenerator;
74
+    /** @var IUserManager */
75
+    protected $userManager;
76
+    /** @var ILogger */
77
+    protected $logger;
78
+    /** @var \OCP\Activity\IManager */
79
+    protected $activityManager;
80
+    /** @var \OCP\Share\IManager */
81
+    protected $shareManager;
82
+    /** @var ISession */
83
+    protected $session;
84
+    /** @var IPreview */
85
+    protected $previewManager;
86
+    /** @var IRootFolder */
87
+    protected $rootFolder;
88
+    /** @var FederatedShareProvider */
89
+    protected $federatedShareProvider;
90
+    /** @var EventDispatcherInterface */
91
+    protected $eventDispatcher;
92
+    /** @var IL10N */
93
+    protected $l10n;
94
+    /** @var Defaults */
95
+    protected $defaults;
96
+
97
+    /**
98
+     * @param string $appName
99
+     * @param IRequest $request
100
+     * @param IConfig $config
101
+     * @param IURLGenerator $urlGenerator
102
+     * @param IUserManager $userManager
103
+     * @param ILogger $logger
104
+     * @param \OCP\Activity\IManager $activityManager
105
+     * @param \OCP\Share\IManager $shareManager
106
+     * @param ISession $session
107
+     * @param IPreview $previewManager
108
+     * @param IRootFolder $rootFolder
109
+     * @param FederatedShareProvider $federatedShareProvider
110
+     * @param EventDispatcherInterface $eventDispatcher
111
+     * @param IL10N $l10n
112
+     * @param Defaults $defaults
113
+     */
114
+    public function __construct($appName,
115
+                                IRequest $request,
116
+                                IConfig $config,
117
+                                IURLGenerator $urlGenerator,
118
+                                IUserManager $userManager,
119
+                                ILogger $logger,
120
+                                \OCP\Activity\IManager $activityManager,
121
+                                \OCP\Share\IManager $shareManager,
122
+                                ISession $session,
123
+                                IPreview $previewManager,
124
+                                IRootFolder $rootFolder,
125
+                                FederatedShareProvider $federatedShareProvider,
126
+                                EventDispatcherInterface $eventDispatcher,
127
+                                IL10N $l10n,
128
+                                Defaults $defaults) {
129
+        parent::__construct($appName, $request);
130
+
131
+        $this->config = $config;
132
+        $this->urlGenerator = $urlGenerator;
133
+        $this->userManager = $userManager;
134
+        $this->logger = $logger;
135
+        $this->activityManager = $activityManager;
136
+        $this->shareManager = $shareManager;
137
+        $this->session = $session;
138
+        $this->previewManager = $previewManager;
139
+        $this->rootFolder = $rootFolder;
140
+        $this->federatedShareProvider = $federatedShareProvider;
141
+        $this->eventDispatcher = $eventDispatcher;
142
+        $this->l10n = $l10n;
143
+        $this->defaults = $defaults;
144
+    }
145
+
146
+    /**
147
+     * @PublicPage
148
+     * @NoCSRFRequired
149
+     *
150
+     * @param string $token
151
+     * @return TemplateResponse|RedirectResponse
152
+     */
153
+    public function showAuthenticate($token) {
154
+        $share = $this->shareManager->getShareByToken($token);
155
+
156
+        if($this->linkShareAuth($share)) {
157
+            return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
158
+        }
159
+
160
+        return new TemplateResponse($this->appName, 'authenticate', array(), 'guest');
161
+    }
162
+
163
+    /**
164
+     * @PublicPage
165
+     * @UseSession
166
+     * @BruteForceProtection(action=publicLinkAuth)
167
+     *
168
+     * Authenticates against password-protected shares
169
+     * @param string $token
170
+     * @param string $password
171
+     * @return RedirectResponse|TemplateResponse|NotFoundResponse
172
+     */
173
+    public function authenticate($token, $password = '') {
174
+
175
+        // Check whether share exists
176
+        try {
177
+            $share = $this->shareManager->getShareByToken($token);
178
+        } catch (ShareNotFound $e) {
179
+            return new NotFoundResponse();
180
+        }
181
+
182
+        $authenticate = $this->linkShareAuth($share, $password);
183
+
184
+        if($authenticate === true) {
185
+            return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
186
+        }
187
+
188
+        $response = new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest');
189
+        $response->throttle();
190
+        return $response;
191
+    }
192
+
193
+    /**
194
+     * Authenticate a link item with the given password.
195
+     * Or use the session if no password is provided.
196
+     *
197
+     * This is a modified version of Helper::authenticate
198
+     * TODO: Try to merge back eventually with Helper::authenticate
199
+     *
200
+     * @param \OCP\Share\IShare $share
201
+     * @param string|null $password
202
+     * @return bool
203
+     */
204
+    private function linkShareAuth(\OCP\Share\IShare $share, $password = null) {
205
+        if ($password !== null) {
206
+            if ($this->shareManager->checkPassword($share, $password)) {
207
+                $this->session->set('public_link_authenticated', (string)$share->getId());
208
+            } else {
209
+                $this->emitAccessShareHook($share, 403, 'Wrong password');
210
+                return false;
211
+            }
212
+        } else {
213
+            // not authenticated ?
214
+            if ( ! $this->session->exists('public_link_authenticated')
215
+                || $this->session->get('public_link_authenticated') !== (string)$share->getId()) {
216
+                return false;
217
+            }
218
+        }
219
+        return true;
220
+    }
221
+
222
+    /**
223
+     * throws hooks when a share is attempted to be accessed
224
+     *
225
+     * @param \OCP\Share\IShare|string $share the Share instance if available,
226
+     * otherwise token
227
+     * @param int $errorCode
228
+     * @param string $errorMessage
229
+     * @throws \OC\HintException
230
+     * @throws \OC\ServerNotAvailableException
231
+     */
232
+    protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') {
233
+        $itemType = $itemSource = $uidOwner = '';
234
+        $token = $share;
235
+        $exception = null;
236
+        if($share instanceof \OCP\Share\IShare) {
237
+            try {
238
+                $token = $share->getToken();
239
+                $uidOwner = $share->getSharedBy();
240
+                $itemType = $share->getNodeType();
241
+                $itemSource = $share->getNodeId();
242
+            } catch (\Exception $e) {
243
+                // we log what we know and pass on the exception afterwards
244
+                $exception = $e;
245
+            }
246
+        }
247
+        \OC_Hook::emit('OCP\Share', 'share_link_access', [
248
+            'itemType' => $itemType,
249
+            'itemSource' => $itemSource,
250
+            'uidOwner' => $uidOwner,
251
+            'token' => $token,
252
+            'errorCode' => $errorCode,
253
+            'errorMessage' => $errorMessage,
254
+        ]);
255
+        if(!is_null($exception)) {
256
+            throw $exception;
257
+        }
258
+    }
259
+
260
+    /**
261
+     * Validate the permissions of the share
262
+     *
263
+     * @param Share\IShare $share
264
+     * @return bool
265
+     */
266
+    private function validateShare(\OCP\Share\IShare $share) {
267
+        return $share->getNode()->isReadable() && $share->getNode()->isShareable();
268
+    }
269
+
270
+    /**
271
+     * @PublicPage
272
+     * @NoCSRFRequired
273
+     *
274
+     * @param string $token
275
+     * @param string $path
276
+     * @return TemplateResponse|RedirectResponse|NotFoundResponse
277
+     * @throws NotFoundException
278
+     * @throws \Exception
279
+     */
280
+    public function showShare($token, $path = '') {
281
+        \OC_User::setIncognitoMode(true);
282
+
283
+        // Check whether share exists
284
+        try {
285
+            $share = $this->shareManager->getShareByToken($token);
286
+        } catch (ShareNotFound $e) {
287
+            $this->emitAccessShareHook($token, 404, 'Share not found');
288
+            return new NotFoundResponse();
289
+        }
290
+
291
+        // Share is password protected - check whether the user is permitted to access the share
292
+        if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
293
+            return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
294
+                array('token' => $token)));
295
+        }
296
+
297
+        if (!$this->validateShare($share)) {
298
+            throw new NotFoundException();
299
+        }
300
+        // We can't get the path of a file share
301
+        try {
302
+            if ($share->getNode() instanceof \OCP\Files\File && $path !== '') {
303
+                $this->emitAccessShareHook($share, 404, 'Share not found');
304
+                throw new NotFoundException();
305
+            }
306
+        } catch (\Exception $e) {
307
+            $this->emitAccessShareHook($share, 404, 'Share not found');
308
+            throw $e;
309
+        }
310
+
311
+        $shareTmpl = [];
312
+        $shareTmpl['displayName'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
313
+        $shareTmpl['owner'] = $share->getShareOwner();
314
+        $shareTmpl['filename'] = $share->getNode()->getName();
315
+        $shareTmpl['directory_path'] = $share->getTarget();
316
+        $shareTmpl['mimetype'] = $share->getNode()->getMimetype();
317
+        $shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype());
318
+        $shareTmpl['dirToken'] = $token;
319
+        $shareTmpl['sharingToken'] = $token;
320
+        $shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
321
+        $shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
322
+        $shareTmpl['dir'] = '';
323
+        $shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize();
324
+        $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize());
325
+
326
+        // Show file list
327
+        $hideFileList = false;
328
+        if ($share->getNode() instanceof \OCP\Files\Folder) {
329
+            /** @var \OCP\Files\Folder $rootFolder */
330
+            $rootFolder = $share->getNode();
331
+
332
+            try {
333
+                $folderNode = $rootFolder->get($path);
334
+            } catch (\OCP\Files\NotFoundException $e) {
335
+                $this->emitAccessShareHook($share, 404, 'Share not found');
336
+                throw new NotFoundException();
337
+            }
338
+
339
+            $shareTmpl['dir'] = $rootFolder->getRelativePath($folderNode->getPath());
340
+
341
+            /*
342 342
 			 * The OC_Util methods require a view. This just uses the node API
343 343
 			 */
344
-			$freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
345
-			if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
346
-				$freeSpace = max($freeSpace, 0);
347
-			} else {
348
-				$freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
349
-			}
350
-
351
-			$hideFileList = !($share->getPermissions() & \OCP\Constants::PERMISSION_READ);
352
-			$maxUploadFilesize = $freeSpace;
353
-
354
-			$folder = new Template('files', 'list', '');
355
-			$folder->assign('dir', $rootFolder->getRelativePath($folderNode->getPath()));
356
-			$folder->assign('dirToken', $token);
357
-			$folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
358
-			$folder->assign('isPublic', true);
359
-			$folder->assign('hideFileList', $hideFileList);
360
-			$folder->assign('publicUploadEnabled', 'no');
361
-			$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
362
-			$folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
363
-			$folder->assign('freeSpace', $freeSpace);
364
-			$folder->assign('usedSpacePercent', 0);
365
-			$folder->assign('trash', false);
366
-			$shareTmpl['folder'] = $folder->fetchPage();
367
-		}
368
-
369
-		$shareTmpl['hideFileList'] = $hideFileList;
370
-		$shareTmpl['shareOwner'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
371
-		$shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $token]);
372
-		$shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]);
373
-		$shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
374
-		$shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
375
-		$shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024);
376
-		$shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
377
-		$shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null);
378
-		$shareTmpl['previewURL'] = $shareTmpl['downloadURL'];
379
-		$ogPreview = '';
380
-		if ($shareTmpl['previewSupported']) {
381
-			$shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute( 'files_sharing.PublicPreview.getPreview',
382
-				['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 't' => $shareTmpl['dirToken']]);
383
-			$ogPreview = $shareTmpl['previewImage'];
384
-
385
-			// We just have direct previews for image files
386
-			if ($share->getNode()->getMimePart() === 'image') {
387
-				$shareTmpl['previewURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.publicpreview.directLink', ['token' => $token]);
388
-				$ogPreview = $shareTmpl['previewURL'];
389
-			}
390
-		} else {
391
-			$shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
392
-			$ogPreview = $shareTmpl['previewImage'];
393
-		}
394
-
395
-		// Load files we need
396
-		\OCP\Util::addScript('files', 'file-upload');
397
-		\OCP\Util::addStyle('files_sharing', 'publicView');
398
-		\OCP\Util::addScript('files_sharing', 'public');
399
-		\OCP\Util::addScript('files', 'fileactions');
400
-		\OCP\Util::addScript('files', 'fileactionsmenu');
401
-		\OCP\Util::addScript('files', 'jquery.fileupload');
402
-		\OCP\Util::addScript('files_sharing', 'files_drop');
403
-
404
-		if (isset($shareTmpl['folder'])) {
405
-			// JS required for folders
406
-			\OCP\Util::addStyle('files', 'merged');
407
-			\OCP\Util::addScript('files', 'filesummary');
408
-			\OCP\Util::addScript('files', 'breadcrumb');
409
-			\OCP\Util::addScript('files', 'fileinfomodel');
410
-			\OCP\Util::addScript('files', 'newfilemenu');
411
-			\OCP\Util::addScript('files', 'files');
412
-			\OCP\Util::addScript('files', 'filelist');
413
-			\OCP\Util::addScript('files', 'keyboardshortcuts');
414
-		}
415
-
416
-		// OpenGraph Support: http://ogp.me/
417
-		\OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $shareTmpl['filename']]);
418
-		\OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->defaults->getName() . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')]);
419
-		\OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]);
420
-		\OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]);
421
-		\OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]);
422
-		\OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $ogPreview]);
423
-
424
-		$this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts');
425
-
426
-		$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
427
-		$csp->addAllowedFrameDomain('\'self\'');
428
-		$response = new TemplateResponse($this->appName, 'public', $shareTmpl, 'base');
429
-		$response->setContentSecurityPolicy($csp);
430
-
431
-		$this->emitAccessShareHook($share);
432
-
433
-		return $response;
434
-	}
435
-
436
-	/**
437
-	 * @PublicPage
438
-	 * @NoCSRFRequired
439
-	 *
440
-	 * @param string $token
441
-	 * @param string $files
442
-	 * @param string $path
443
-	 * @param string $downloadStartSecret
444
-	 * @return void|\OCP\AppFramework\Http\Response
445
-	 * @throws NotFoundException
446
-	 */
447
-	public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
448
-		\OC_User::setIncognitoMode(true);
449
-
450
-		$share = $this->shareManager->getShareByToken($token);
451
-
452
-		if(!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
453
-			return new \OCP\AppFramework\Http\DataResponse('Share is read-only');
454
-		}
455
-
456
-		// Share is password protected - check whether the user is permitted to access the share
457
-		if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
458
-			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
459
-				['token' => $token]));
460
-		}
461
-
462
-		$files_list = null;
463
-		if (!is_null($files)) { // download selected files
464
-			$files_list = json_decode($files);
465
-			// in case we get only a single file
466
-			if ($files_list === null) {
467
-				$files_list = [$files];
468
-			}
469
-			// Just in case $files is a single int like '1234'
470
-			if (!is_array($files_list)) {
471
-				$files_list = [$files_list];
472
-			}
473
-		}
474
-
475
-		$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
476
-		$originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
477
-
478
-		if (!$this->validateShare($share)) {
479
-			throw new NotFoundException();
480
-		}
481
-
482
-		// Single file share
483
-		if ($share->getNode() instanceof \OCP\Files\File) {
484
-			// Single file download
485
-			$this->singleFileDownloaded($share, $share->getNode());
486
-		}
487
-		// Directory share
488
-		else {
489
-			/** @var \OCP\Files\Folder $node */
490
-			$node = $share->getNode();
491
-
492
-			// Try to get the path
493
-			if ($path !== '') {
494
-				try {
495
-					$node = $node->get($path);
496
-				} catch (NotFoundException $e) {
497
-					$this->emitAccessShareHook($share, 404, 'Share not found');
498
-					return new NotFoundResponse();
499
-				}
500
-			}
501
-
502
-			$originalSharePath = $userFolder->getRelativePath($node->getPath());
503
-
504
-			if ($node instanceof \OCP\Files\File) {
505
-				// Single file download
506
-				$this->singleFileDownloaded($share, $share->getNode());
507
-			} else if (!empty($files_list)) {
508
-				$this->fileListDownloaded($share, $files_list, $node);
509
-			} else {
510
-				// The folder is downloaded
511
-				$this->singleFileDownloaded($share, $share->getNode());
512
-			}
513
-		}
514
-
515
-		/* FIXME: We should do this all nicely in OCP */
516
-		OC_Util::tearDownFS();
517
-		OC_Util::setupFS($share->getShareOwner());
518
-
519
-		/**
520
-		 * this sets a cookie to be able to recognize the start of the download
521
-		 * the content must not be longer than 32 characters and must only contain
522
-		 * alphanumeric characters
523
-		 */
524
-		if (!empty($downloadStartSecret)
525
-			&& !isset($downloadStartSecret[32])
526
-			&& preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
527
-
528
-			// FIXME: set on the response once we use an actual app framework response
529
-			setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');
530
-		}
531
-
532
-		$this->emitAccessShareHook($share);
533
-
534
-		$server_params = array( 'head' => $this->request->getMethod() === 'HEAD' );
535
-
536
-		/**
537
-		 * Http range requests support
538
-		 */
539
-		if (isset($_SERVER['HTTP_RANGE'])) {
540
-			$server_params['range'] = $this->request->getHeader('Range');
541
-		}
542
-
543
-		// download selected files
544
-		if (!is_null($files) && $files !== '') {
545
-			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
546
-			// after dispatching the request which results in a "Cannot modify header information" notice.
547
-			OC_Files::get($originalSharePath, $files_list, $server_params);
548
-			exit();
549
-		} else {
550
-			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
551
-			// after dispatching the request which results in a "Cannot modify header information" notice.
552
-			OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params);
553
-			exit();
554
-		}
555
-	}
556
-
557
-	/**
558
-	 * create activity for every downloaded file
559
-	 *
560
-	 * @param Share\IShare $share
561
-	 * @param array $files_list
562
-	 * @param \OCP\Files\Folder $node
563
-	 */
564
-	protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) {
565
-		foreach ($files_list as $file) {
566
-			$subNode = $node->get($file);
567
-			$this->singleFileDownloaded($share, $subNode);
568
-		}
569
-
570
-	}
571
-
572
-	/**
573
-	 * create activity if a single file was downloaded from a link share
574
-	 *
575
-	 * @param Share\IShare $share
576
-	 */
577
-	protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) {
578
-
579
-		$fileId = $node->getId();
580
-
581
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
582
-		$userNodeList = $userFolder->getById($fileId);
583
-		$userNode = $userNodeList[0];
584
-		$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
585
-		$userPath = $userFolder->getRelativePath($userNode->getPath());
586
-		$ownerPath = $ownerFolder->getRelativePath($node->getPath());
587
-
588
-		$parameters = [$userPath];
589
-
590
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
591
-			if ($node instanceof \OCP\Files\File) {
592
-				$subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED;
593
-			} else {
594
-				$subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED;
595
-			}
596
-			$parameters[] = $share->getSharedWith();
597
-		} else {
598
-			if ($node instanceof \OCP\Files\File) {
599
-				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
600
-			} else {
601
-				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
602
-			}
603
-		}
604
-
605
-		$this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath);
606
-
607
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
608
-			$parameters[0] = $ownerPath;
609
-			$this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath);
610
-		}
611
-	}
612
-
613
-	/**
614
-	 * publish activity
615
-	 *
616
-	 * @param string $subject
617
-	 * @param array $parameters
618
-	 * @param string $affectedUser
619
-	 * @param int $fileId
620
-	 * @param string $filePath
621
-	 */
622
-	protected function publishActivity($subject,
623
-										array $parameters,
624
-										$affectedUser,
625
-										$fileId,
626
-										$filePath) {
627
-
628
-		$event = $this->activityManager->generateEvent();
629
-		$event->setApp('files_sharing')
630
-			->setType('public_links')
631
-			->setSubject($subject, $parameters)
632
-			->setAffectedUser($affectedUser)
633
-			->setObject('files', $fileId, $filePath);
634
-		$this->activityManager->publish($event);
635
-	}
344
+            $freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
345
+            if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
346
+                $freeSpace = max($freeSpace, 0);
347
+            } else {
348
+                $freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
349
+            }
350
+
351
+            $hideFileList = !($share->getPermissions() & \OCP\Constants::PERMISSION_READ);
352
+            $maxUploadFilesize = $freeSpace;
353
+
354
+            $folder = new Template('files', 'list', '');
355
+            $folder->assign('dir', $rootFolder->getRelativePath($folderNode->getPath()));
356
+            $folder->assign('dirToken', $token);
357
+            $folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
358
+            $folder->assign('isPublic', true);
359
+            $folder->assign('hideFileList', $hideFileList);
360
+            $folder->assign('publicUploadEnabled', 'no');
361
+            $folder->assign('uploadMaxFilesize', $maxUploadFilesize);
362
+            $folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
363
+            $folder->assign('freeSpace', $freeSpace);
364
+            $folder->assign('usedSpacePercent', 0);
365
+            $folder->assign('trash', false);
366
+            $shareTmpl['folder'] = $folder->fetchPage();
367
+        }
368
+
369
+        $shareTmpl['hideFileList'] = $hideFileList;
370
+        $shareTmpl['shareOwner'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
371
+        $shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $token]);
372
+        $shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]);
373
+        $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
374
+        $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
375
+        $shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024);
376
+        $shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
377
+        $shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null);
378
+        $shareTmpl['previewURL'] = $shareTmpl['downloadURL'];
379
+        $ogPreview = '';
380
+        if ($shareTmpl['previewSupported']) {
381
+            $shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute( 'files_sharing.PublicPreview.getPreview',
382
+                ['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 't' => $shareTmpl['dirToken']]);
383
+            $ogPreview = $shareTmpl['previewImage'];
384
+
385
+            // We just have direct previews for image files
386
+            if ($share->getNode()->getMimePart() === 'image') {
387
+                $shareTmpl['previewURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.publicpreview.directLink', ['token' => $token]);
388
+                $ogPreview = $shareTmpl['previewURL'];
389
+            }
390
+        } else {
391
+            $shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
392
+            $ogPreview = $shareTmpl['previewImage'];
393
+        }
394
+
395
+        // Load files we need
396
+        \OCP\Util::addScript('files', 'file-upload');
397
+        \OCP\Util::addStyle('files_sharing', 'publicView');
398
+        \OCP\Util::addScript('files_sharing', 'public');
399
+        \OCP\Util::addScript('files', 'fileactions');
400
+        \OCP\Util::addScript('files', 'fileactionsmenu');
401
+        \OCP\Util::addScript('files', 'jquery.fileupload');
402
+        \OCP\Util::addScript('files_sharing', 'files_drop');
403
+
404
+        if (isset($shareTmpl['folder'])) {
405
+            // JS required for folders
406
+            \OCP\Util::addStyle('files', 'merged');
407
+            \OCP\Util::addScript('files', 'filesummary');
408
+            \OCP\Util::addScript('files', 'breadcrumb');
409
+            \OCP\Util::addScript('files', 'fileinfomodel');
410
+            \OCP\Util::addScript('files', 'newfilemenu');
411
+            \OCP\Util::addScript('files', 'files');
412
+            \OCP\Util::addScript('files', 'filelist');
413
+            \OCP\Util::addScript('files', 'keyboardshortcuts');
414
+        }
415
+
416
+        // OpenGraph Support: http://ogp.me/
417
+        \OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $shareTmpl['filename']]);
418
+        \OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->defaults->getName() . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')]);
419
+        \OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]);
420
+        \OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]);
421
+        \OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]);
422
+        \OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $ogPreview]);
423
+
424
+        $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts');
425
+
426
+        $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
427
+        $csp->addAllowedFrameDomain('\'self\'');
428
+        $response = new TemplateResponse($this->appName, 'public', $shareTmpl, 'base');
429
+        $response->setContentSecurityPolicy($csp);
430
+
431
+        $this->emitAccessShareHook($share);
432
+
433
+        return $response;
434
+    }
435
+
436
+    /**
437
+     * @PublicPage
438
+     * @NoCSRFRequired
439
+     *
440
+     * @param string $token
441
+     * @param string $files
442
+     * @param string $path
443
+     * @param string $downloadStartSecret
444
+     * @return void|\OCP\AppFramework\Http\Response
445
+     * @throws NotFoundException
446
+     */
447
+    public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
448
+        \OC_User::setIncognitoMode(true);
449
+
450
+        $share = $this->shareManager->getShareByToken($token);
451
+
452
+        if(!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
453
+            return new \OCP\AppFramework\Http\DataResponse('Share is read-only');
454
+        }
455
+
456
+        // Share is password protected - check whether the user is permitted to access the share
457
+        if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
458
+            return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
459
+                ['token' => $token]));
460
+        }
461
+
462
+        $files_list = null;
463
+        if (!is_null($files)) { // download selected files
464
+            $files_list = json_decode($files);
465
+            // in case we get only a single file
466
+            if ($files_list === null) {
467
+                $files_list = [$files];
468
+            }
469
+            // Just in case $files is a single int like '1234'
470
+            if (!is_array($files_list)) {
471
+                $files_list = [$files_list];
472
+            }
473
+        }
474
+
475
+        $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
476
+        $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
477
+
478
+        if (!$this->validateShare($share)) {
479
+            throw new NotFoundException();
480
+        }
481
+
482
+        // Single file share
483
+        if ($share->getNode() instanceof \OCP\Files\File) {
484
+            // Single file download
485
+            $this->singleFileDownloaded($share, $share->getNode());
486
+        }
487
+        // Directory share
488
+        else {
489
+            /** @var \OCP\Files\Folder $node */
490
+            $node = $share->getNode();
491
+
492
+            // Try to get the path
493
+            if ($path !== '') {
494
+                try {
495
+                    $node = $node->get($path);
496
+                } catch (NotFoundException $e) {
497
+                    $this->emitAccessShareHook($share, 404, 'Share not found');
498
+                    return new NotFoundResponse();
499
+                }
500
+            }
501
+
502
+            $originalSharePath = $userFolder->getRelativePath($node->getPath());
503
+
504
+            if ($node instanceof \OCP\Files\File) {
505
+                // Single file download
506
+                $this->singleFileDownloaded($share, $share->getNode());
507
+            } else if (!empty($files_list)) {
508
+                $this->fileListDownloaded($share, $files_list, $node);
509
+            } else {
510
+                // The folder is downloaded
511
+                $this->singleFileDownloaded($share, $share->getNode());
512
+            }
513
+        }
514
+
515
+        /* FIXME: We should do this all nicely in OCP */
516
+        OC_Util::tearDownFS();
517
+        OC_Util::setupFS($share->getShareOwner());
518
+
519
+        /**
520
+         * this sets a cookie to be able to recognize the start of the download
521
+         * the content must not be longer than 32 characters and must only contain
522
+         * alphanumeric characters
523
+         */
524
+        if (!empty($downloadStartSecret)
525
+            && !isset($downloadStartSecret[32])
526
+            && preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
527
+
528
+            // FIXME: set on the response once we use an actual app framework response
529
+            setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');
530
+        }
531
+
532
+        $this->emitAccessShareHook($share);
533
+
534
+        $server_params = array( 'head' => $this->request->getMethod() === 'HEAD' );
535
+
536
+        /**
537
+         * Http range requests support
538
+         */
539
+        if (isset($_SERVER['HTTP_RANGE'])) {
540
+            $server_params['range'] = $this->request->getHeader('Range');
541
+        }
542
+
543
+        // download selected files
544
+        if (!is_null($files) && $files !== '') {
545
+            // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
546
+            // after dispatching the request which results in a "Cannot modify header information" notice.
547
+            OC_Files::get($originalSharePath, $files_list, $server_params);
548
+            exit();
549
+        } else {
550
+            // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
551
+            // after dispatching the request which results in a "Cannot modify header information" notice.
552
+            OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params);
553
+            exit();
554
+        }
555
+    }
556
+
557
+    /**
558
+     * create activity for every downloaded file
559
+     *
560
+     * @param Share\IShare $share
561
+     * @param array $files_list
562
+     * @param \OCP\Files\Folder $node
563
+     */
564
+    protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) {
565
+        foreach ($files_list as $file) {
566
+            $subNode = $node->get($file);
567
+            $this->singleFileDownloaded($share, $subNode);
568
+        }
569
+
570
+    }
571
+
572
+    /**
573
+     * create activity if a single file was downloaded from a link share
574
+     *
575
+     * @param Share\IShare $share
576
+     */
577
+    protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) {
578
+
579
+        $fileId = $node->getId();
580
+
581
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
582
+        $userNodeList = $userFolder->getById($fileId);
583
+        $userNode = $userNodeList[0];
584
+        $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
585
+        $userPath = $userFolder->getRelativePath($userNode->getPath());
586
+        $ownerPath = $ownerFolder->getRelativePath($node->getPath());
587
+
588
+        $parameters = [$userPath];
589
+
590
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
591
+            if ($node instanceof \OCP\Files\File) {
592
+                $subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED;
593
+            } else {
594
+                $subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED;
595
+            }
596
+            $parameters[] = $share->getSharedWith();
597
+        } else {
598
+            if ($node instanceof \OCP\Files\File) {
599
+                $subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
600
+            } else {
601
+                $subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
602
+            }
603
+        }
604
+
605
+        $this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath);
606
+
607
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
608
+            $parameters[0] = $ownerPath;
609
+            $this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath);
610
+        }
611
+    }
612
+
613
+    /**
614
+     * publish activity
615
+     *
616
+     * @param string $subject
617
+     * @param array $parameters
618
+     * @param string $affectedUser
619
+     * @param int $fileId
620
+     * @param string $filePath
621
+     */
622
+    protected function publishActivity($subject,
623
+                                        array $parameters,
624
+                                        $affectedUser,
625
+                                        $fileId,
626
+                                        $filePath) {
627
+
628
+        $event = $this->activityManager->generateEvent();
629
+        $event->setApp('files_sharing')
630
+            ->setType('public_links')
631
+            ->setSubject($subject, $parameters)
632
+            ->setAffectedUser($affectedUser)
633
+            ->setObject('files', $fileId, $filePath);
634
+        $this->activityManager->publish($event);
635
+    }
636 636
 
637 637
 
638 638
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Controller/AjaxController.php 1 patch
Indentation   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -39,84 +39,84 @@
 block discarded – undo
39 39
 use OCP\IUserSession;
40 40
 
41 41
 class AjaxController extends Controller {
42
-	/** @var RSA */
43
-	private $rsaMechanism;
44
-	/** @var GlobalAuth  */
45
-	private $globalAuth;
46
-	/** @var IUserSession */
47
-	private $userSession;
48
-	/** @var IGroupManager */
49
-	private $groupManager;
42
+    /** @var RSA */
43
+    private $rsaMechanism;
44
+    /** @var GlobalAuth  */
45
+    private $globalAuth;
46
+    /** @var IUserSession */
47
+    private $userSession;
48
+    /** @var IGroupManager */
49
+    private $groupManager;
50 50
 
51
-	/**
52
-	 * @param string $appName
53
-	 * @param IRequest $request
54
-	 * @param RSA $rsaMechanism
55
-	 * @param GlobalAuth $globalAuth
56
-	 * @param IUserSession $userSession
57
-	 * @param IGroupManager $groupManager
58
-	 */
59
-	public function __construct($appName,
60
-								IRequest $request,
61
-								RSA $rsaMechanism,
62
-								GlobalAuth $globalAuth,
63
-								IUserSession $userSession,
64
-								IGroupManager $groupManager) {
65
-		parent::__construct($appName, $request);
66
-		$this->rsaMechanism = $rsaMechanism;
67
-		$this->globalAuth = $globalAuth;
68
-		$this->userSession = $userSession;
69
-		$this->groupManager = $groupManager;
70
-	}
51
+    /**
52
+     * @param string $appName
53
+     * @param IRequest $request
54
+     * @param RSA $rsaMechanism
55
+     * @param GlobalAuth $globalAuth
56
+     * @param IUserSession $userSession
57
+     * @param IGroupManager $groupManager
58
+     */
59
+    public function __construct($appName,
60
+                                IRequest $request,
61
+                                RSA $rsaMechanism,
62
+                                GlobalAuth $globalAuth,
63
+                                IUserSession $userSession,
64
+                                IGroupManager $groupManager) {
65
+        parent::__construct($appName, $request);
66
+        $this->rsaMechanism = $rsaMechanism;
67
+        $this->globalAuth = $globalAuth;
68
+        $this->userSession = $userSession;
69
+        $this->groupManager = $groupManager;
70
+    }
71 71
 
72
-	/**
73
-	 * @param int $keyLength
74
-	 * @return array
75
-	 */
76
-	private function generateSshKeys($keyLength) {
77
-		$key = $this->rsaMechanism->createKey($keyLength);
78
-		// Replace the placeholder label with a more meaningful one
79
-		$key['publickey'] = str_replace('phpseclib-generated-key', gethostname(), $key['publickey']);
72
+    /**
73
+     * @param int $keyLength
74
+     * @return array
75
+     */
76
+    private function generateSshKeys($keyLength) {
77
+        $key = $this->rsaMechanism->createKey($keyLength);
78
+        // Replace the placeholder label with a more meaningful one
79
+        $key['publickey'] = str_replace('phpseclib-generated-key', gethostname(), $key['publickey']);
80 80
 
81
-		return $key;
82
-	}
81
+        return $key;
82
+    }
83 83
 
84
-	/**
85
-	 * Generates an SSH public/private key pair.
86
-	 *
87
-	 * @NoAdminRequired
88
-	 * @param int $keyLength
89
-	 */
90
-	public function getSshKeys($keyLength = 1024) {
91
-		$key = $this->generateSshKeys($keyLength);
92
-		return new JSONResponse(
93
-			array('data' => array(
94
-				'private_key' => $key['privatekey'],
95
-				'public_key' => $key['publickey']
96
-			),
97
-			'status' => 'success'
98
-		));
99
-	}
84
+    /**
85
+     * Generates an SSH public/private key pair.
86
+     *
87
+     * @NoAdminRequired
88
+     * @param int $keyLength
89
+     */
90
+    public function getSshKeys($keyLength = 1024) {
91
+        $key = $this->generateSshKeys($keyLength);
92
+        return new JSONResponse(
93
+            array('data' => array(
94
+                'private_key' => $key['privatekey'],
95
+                'public_key' => $key['publickey']
96
+            ),
97
+            'status' => 'success'
98
+        ));
99
+    }
100 100
 
101
-	/**
102
-	 * @NoAdminRequired
103
-	 *
104
-	 * @param string $uid
105
-	 * @param string $user
106
-	 * @param string $password
107
-	 * @return bool
108
-	 */
109
-	public function saveGlobalCredentials($uid, $user, $password) {
110
-		$currentUser = $this->userSession->getUser();
101
+    /**
102
+     * @NoAdminRequired
103
+     *
104
+     * @param string $uid
105
+     * @param string $user
106
+     * @param string $password
107
+     * @return bool
108
+     */
109
+    public function saveGlobalCredentials($uid, $user, $password) {
110
+        $currentUser = $this->userSession->getUser();
111 111
 
112
-		// Non-admins can only edit their own credentials
113
-		$allowedToEdit = ($this->groupManager->isAdmin($currentUser->getUID()) || $currentUser->getUID() === $uid);
112
+        // Non-admins can only edit their own credentials
113
+        $allowedToEdit = ($this->groupManager->isAdmin($currentUser->getUID()) || $currentUser->getUID() === $uid);
114 114
 
115
-		if ($allowedToEdit) {
116
-			$this->globalAuth->saveAuth($uid, $user, $password);
117
-			return true;
118
-		} else {
119
-			return false;
120
-		}
121
-	}
115
+        if ($allowedToEdit) {
116
+            $this->globalAuth->saveAuth($uid, $user, $password);
117
+            return true;
118
+        } else {
119
+            return false;
120
+        }
121
+    }
122 122
 }
Please login to merge, or discard this patch.
lib/private/legacy/util.php 1 patch
Indentation   +1455 added lines, -1455 removed lines patch added patch discarded remove patch
@@ -65,1463 +65,1463 @@
 block discarded – undo
65 65
 use OCP\IUser;
66 66
 
67 67
 class OC_Util {
68
-	public static $scripts = array();
69
-	public static $styles = array();
70
-	public static $headers = array();
71
-	private static $rootMounted = false;
72
-	private static $fsSetup = false;
73
-
74
-	/** @var array Local cache of version.php */
75
-	private static $versionCache = null;
76
-
77
-	protected static function getAppManager() {
78
-		return \OC::$server->getAppManager();
79
-	}
80
-
81
-	private static function initLocalStorageRootFS() {
82
-		// mount local file backend as root
83
-		$configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
84
-		//first set up the local "root" storage
85
-		\OC\Files\Filesystem::initMountManager();
86
-		if (!self::$rootMounted) {
87
-			\OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir' => $configDataDirectory), '/');
88
-			self::$rootMounted = true;
89
-		}
90
-	}
91
-
92
-	/**
93
-	 * mounting an object storage as the root fs will in essence remove the
94
-	 * necessity of a data folder being present.
95
-	 * TODO make home storage aware of this and use the object storage instead of local disk access
96
-	 *
97
-	 * @param array $config containing 'class' and optional 'arguments'
98
-	 * @suppress PhanDeprecatedFunction
99
-	 */
100
-	private static function initObjectStoreRootFS($config) {
101
-		// check misconfiguration
102
-		if (empty($config['class'])) {
103
-			\OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
104
-		}
105
-		if (!isset($config['arguments'])) {
106
-			$config['arguments'] = array();
107
-		}
108
-
109
-		// instantiate object store implementation
110
-		$name = $config['class'];
111
-		if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
112
-			$segments = explode('\\', $name);
113
-			OC_App::loadApp(strtolower($segments[1]));
114
-		}
115
-		$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
116
-		// mount with plain / root object store implementation
117
-		$config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
118
-
119
-		// mount object storage as root
120
-		\OC\Files\Filesystem::initMountManager();
121
-		if (!self::$rootMounted) {
122
-			\OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
123
-			self::$rootMounted = true;
124
-		}
125
-	}
126
-
127
-	/**
128
-	 * mounting an object storage as the root fs will in essence remove the
129
-	 * necessity of a data folder being present.
130
-	 *
131
-	 * @param array $config containing 'class' and optional 'arguments'
132
-	 * @suppress PhanDeprecatedFunction
133
-	 */
134
-	private static function initObjectStoreMultibucketRootFS($config) {
135
-		// check misconfiguration
136
-		if (empty($config['class'])) {
137
-			\OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
138
-		}
139
-		if (!isset($config['arguments'])) {
140
-			$config['arguments'] = array();
141
-		}
142
-
143
-		// instantiate object store implementation
144
-		$name = $config['class'];
145
-		if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
146
-			$segments = explode('\\', $name);
147
-			OC_App::loadApp(strtolower($segments[1]));
148
-		}
149
-
150
-		if (!isset($config['arguments']['bucket'])) {
151
-			$config['arguments']['bucket'] = '';
152
-		}
153
-		// put the root FS always in first bucket for multibucket configuration
154
-		$config['arguments']['bucket'] .= '0';
155
-
156
-		$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
157
-		// mount with plain / root object store implementation
158
-		$config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
159
-
160
-		// mount object storage as root
161
-		\OC\Files\Filesystem::initMountManager();
162
-		if (!self::$rootMounted) {
163
-			\OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
164
-			self::$rootMounted = true;
165
-		}
166
-	}
167
-
168
-	/**
169
-	 * Can be set up
170
-	 *
171
-	 * @param string $user
172
-	 * @return boolean
173
-	 * @description configure the initial filesystem based on the configuration
174
-	 * @suppress PhanDeprecatedFunction
175
-	 * @suppress PhanAccessMethodInternal
176
-	 */
177
-	public static function setupFS($user = '') {
178
-		//setting up the filesystem twice can only lead to trouble
179
-		if (self::$fsSetup) {
180
-			return false;
181
-		}
182
-
183
-		\OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
184
-
185
-		// If we are not forced to load a specific user we load the one that is logged in
186
-		if ($user === null) {
187
-			$user = '';
188
-		} else if ($user == "" && \OC::$server->getUserSession()->isLoggedIn()) {
189
-			$user = OC_User::getUser();
190
-		}
191
-
192
-		// load all filesystem apps before, so no setup-hook gets lost
193
-		OC_App::loadApps(array('filesystem'));
194
-
195
-		// the filesystem will finish when $user is not empty,
196
-		// mark fs setup here to avoid doing the setup from loading
197
-		// OC_Filesystem
198
-		if ($user != '') {
199
-			self::$fsSetup = true;
200
-		}
201
-
202
-		\OC\Files\Filesystem::initMountManager();
203
-
204
-		\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
205
-		\OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
206
-			if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
207
-				/** @var \OC\Files\Storage\Common $storage */
208
-				$storage->setMountOptions($mount->getOptions());
209
-			}
210
-			return $storage;
211
-		});
212
-
213
-		\OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) {
214
-			if (!$mount->getOption('enable_sharing', true)) {
215
-				return new \OC\Files\Storage\Wrapper\PermissionsMask([
216
-					'storage' => $storage,
217
-					'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
218
-				]);
219
-			}
220
-			return $storage;
221
-		});
222
-
223
-		// install storage availability wrapper, before most other wrappers
224
-		\OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) {
225
-			if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
226
-				return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
227
-			}
228
-			return $storage;
229
-		});
230
-
231
-		\OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
232
-			if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
233
-				return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
234
-			}
235
-			return $storage;
236
-		});
237
-
238
-		\OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
239
-			// set up quota for home storages, even for other users
240
-			// which can happen when using sharing
241
-
242
-			/**
243
-			 * @var \OC\Files\Storage\Storage $storage
244
-			 */
245
-			if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
246
-				|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
247
-			) {
248
-				/** @var \OC\Files\Storage\Home $storage */
249
-				if (is_object($storage->getUser())) {
250
-					$user = $storage->getUser()->getUID();
251
-					$quota = OC_Util::getUserQuota($user);
252
-					if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
253
-						return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files'));
254
-					}
255
-				}
256
-			}
257
-
258
-			return $storage;
259
-		});
260
-
261
-		OC_Hook::emit('OC_Filesystem', 'preSetup', array('user' => $user));
262
-		\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(true);
263
-
264
-		//check if we are using an object storage
265
-		$objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
266
-		$objectStoreMultibucket = \OC::$server->getSystemConfig()->getValue('objectstore_multibucket', null);
267
-
268
-		// use the same order as in ObjectHomeMountProvider
269
-		if (isset($objectStoreMultibucket)) {
270
-			self::initObjectStoreMultibucketRootFS($objectStoreMultibucket);
271
-		} elseif (isset($objectStore)) {
272
-			self::initObjectStoreRootFS($objectStore);
273
-		} else {
274
-			self::initLocalStorageRootFS();
275
-		}
276
-
277
-		if ($user != '' && !\OC::$server->getUserManager()->userExists($user)) {
278
-			\OC::$server->getEventLogger()->end('setup_fs');
279
-			return false;
280
-		}
281
-
282
-		//if we aren't logged in, there is no use to set up the filesystem
283
-		if ($user != "") {
284
-
285
-			$userDir = '/' . $user . '/files';
286
-
287
-			//jail the user into his "home" directory
288
-			\OC\Files\Filesystem::init($user, $userDir);
289
-
290
-			OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir));
291
-		}
292
-		\OC::$server->getEventLogger()->end('setup_fs');
293
-		return true;
294
-	}
295
-
296
-	/**
297
-	 * check if a password is required for each public link
298
-	 *
299
-	 * @return boolean
300
-	 * @suppress PhanDeprecatedFunction
301
-	 */
302
-	public static function isPublicLinkPasswordRequired() {
303
-		$enforcePassword = \OC::$server->getConfig()->getAppValue('core', 'shareapi_enforce_links_password', 'no');
304
-		return $enforcePassword === 'yes';
305
-	}
306
-
307
-	/**
308
-	 * check if sharing is disabled for the current user
309
-	 * @param IConfig $config
310
-	 * @param IGroupManager $groupManager
311
-	 * @param IUser|null $user
312
-	 * @return bool
313
-	 */
314
-	public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
315
-		if ($config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
316
-			$groupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
317
-			$excludedGroups = json_decode($groupsList);
318
-			if (is_null($excludedGroups)) {
319
-				$excludedGroups = explode(',', $groupsList);
320
-				$newValue = json_encode($excludedGroups);
321
-				$config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
322
-			}
323
-			$usersGroups = $groupManager->getUserGroupIds($user);
324
-			if (!empty($usersGroups)) {
325
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
326
-				// if the user is only in groups which are disabled for sharing then
327
-				// sharing is also disabled for the user
328
-				if (empty($remainingGroups)) {
329
-					return true;
330
-				}
331
-			}
332
-		}
333
-		return false;
334
-	}
335
-
336
-	/**
337
-	 * check if share API enforces a default expire date
338
-	 *
339
-	 * @return boolean
340
-	 * @suppress PhanDeprecatedFunction
341
-	 */
342
-	public static function isDefaultExpireDateEnforced() {
343
-		$isDefaultExpireDateEnabled = \OC::$server->getConfig()->getAppValue('core', 'shareapi_default_expire_date', 'no');
344
-		$enforceDefaultExpireDate = false;
345
-		if ($isDefaultExpireDateEnabled === 'yes') {
346
-			$value = \OC::$server->getConfig()->getAppValue('core', 'shareapi_enforce_expire_date', 'no');
347
-			$enforceDefaultExpireDate = $value === 'yes';
348
-		}
349
-
350
-		return $enforceDefaultExpireDate;
351
-	}
352
-
353
-	/**
354
-	 * Get the quota of a user
355
-	 *
356
-	 * @param string $userId
357
-	 * @return float Quota bytes
358
-	 */
359
-	public static function getUserQuota($userId) {
360
-		$user = \OC::$server->getUserManager()->get($userId);
361
-		if (is_null($user)) {
362
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
363
-		}
364
-		$userQuota = $user->getQuota();
365
-		if($userQuota === 'none') {
366
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
367
-		}
368
-		return OC_Helper::computerFileSize($userQuota);
369
-	}
370
-
371
-	/**
372
-	 * copies the skeleton to the users /files
373
-	 *
374
-	 * @param String $userId
375
-	 * @param \OCP\Files\Folder $userDirectory
376
-	 * @throws \RuntimeException
377
-	 * @suppress PhanDeprecatedFunction
378
-	 */
379
-	public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
380
-
381
-		$plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
382
-		$userLang = \OC::$server->getL10NFactory()->findLanguage();
383
-		$skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
384
-
385
-		if (!file_exists($skeletonDirectory)) {
386
-			$dialectStart = strpos($userLang, '_');
387
-			if ($dialectStart !== false) {
388
-				$skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
389
-			}
390
-			if ($dialectStart === false || !file_exists($skeletonDirectory)) {
391
-				$skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
392
-			}
393
-			if (!file_exists($skeletonDirectory)) {
394
-				$skeletonDirectory = '';
395
-			}
396
-		}
397
-
398
-		$instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
399
-
400
-		if ($instanceId === null) {
401
-			throw new \RuntimeException('no instance id!');
402
-		}
403
-		$appdata = 'appdata_' . $instanceId;
404
-		if ($userId === $appdata) {
405
-			throw new \RuntimeException('username is reserved name: ' . $appdata);
406
-		}
407
-
408
-		if (!empty($skeletonDirectory)) {
409
-			\OCP\Util::writeLog(
410
-				'files_skeleton',
411
-				'copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'),
412
-				\OCP\Util::DEBUG
413
-			);
414
-			self::copyr($skeletonDirectory, $userDirectory);
415
-			// update the file cache
416
-			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
417
-		}
418
-	}
419
-
420
-	/**
421
-	 * copies a directory recursively by using streams
422
-	 *
423
-	 * @param string $source
424
-	 * @param \OCP\Files\Folder $target
425
-	 * @return void
426
-	 */
427
-	public static function copyr($source, \OCP\Files\Folder $target) {
428
-		$logger = \OC::$server->getLogger();
429
-
430
-		// Verify if folder exists
431
-		$dir = opendir($source);
432
-		if($dir === false) {
433
-			$logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
434
-			return;
435
-		}
436
-
437
-		// Copy the files
438
-		while (false !== ($file = readdir($dir))) {
439
-			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
440
-				if (is_dir($source . '/' . $file)) {
441
-					$child = $target->newFolder($file);
442
-					self::copyr($source . '/' . $file, $child);
443
-				} else {
444
-					$child = $target->newFile($file);
445
-					$sourceStream = fopen($source . '/' . $file, 'r');
446
-					if($sourceStream === false) {
447
-						$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
448
-						closedir($dir);
449
-						return;
450
-					}
451
-					stream_copy_to_stream($sourceStream, $child->fopen('w'));
452
-				}
453
-			}
454
-		}
455
-		closedir($dir);
456
-	}
457
-
458
-	/**
459
-	 * @return void
460
-	 * @suppress PhanUndeclaredMethod
461
-	 */
462
-	public static function tearDownFS() {
463
-		\OC\Files\Filesystem::tearDown();
464
-		\OC::$server->getRootFolder()->clearCache();
465
-		self::$fsSetup = false;
466
-		self::$rootMounted = false;
467
-	}
468
-
469
-	/**
470
-	 * get the current installed version of ownCloud
471
-	 *
472
-	 * @return array
473
-	 */
474
-	public static function getVersion() {
475
-		OC_Util::loadVersion();
476
-		return self::$versionCache['OC_Version'];
477
-	}
478
-
479
-	/**
480
-	 * get the current installed version string of ownCloud
481
-	 *
482
-	 * @return string
483
-	 */
484
-	public static function getVersionString() {
485
-		OC_Util::loadVersion();
486
-		return self::$versionCache['OC_VersionString'];
487
-	}
488
-
489
-	/**
490
-	 * @deprecated the value is of no use anymore
491
-	 * @return string
492
-	 */
493
-	public static function getEditionString() {
494
-		return '';
495
-	}
496
-
497
-	/**
498
-	 * @description get the update channel of the current installed of ownCloud.
499
-	 * @return string
500
-	 */
501
-	public static function getChannel() {
502
-		OC_Util::loadVersion();
503
-		return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
504
-	}
505
-
506
-	/**
507
-	 * @description get the build number of the current installed of ownCloud.
508
-	 * @return string
509
-	 */
510
-	public static function getBuild() {
511
-		OC_Util::loadVersion();
512
-		return self::$versionCache['OC_Build'];
513
-	}
514
-
515
-	/**
516
-	 * @description load the version.php into the session as cache
517
-	 * @suppress PhanUndeclaredVariable
518
-	 */
519
-	private static function loadVersion() {
520
-		if (self::$versionCache !== null) {
521
-			return;
522
-		}
523
-
524
-		$timestamp = filemtime(OC::$SERVERROOT . '/version.php');
525
-		require OC::$SERVERROOT . '/version.php';
526
-		/** @var $timestamp int */
527
-		self::$versionCache['OC_Version_Timestamp'] = $timestamp;
528
-		/** @var $OC_Version string */
529
-		self::$versionCache['OC_Version'] = $OC_Version;
530
-		/** @var $OC_VersionString string */
531
-		self::$versionCache['OC_VersionString'] = $OC_VersionString;
532
-		/** @var $OC_Build string */
533
-		self::$versionCache['OC_Build'] = $OC_Build;
534
-
535
-		/** @var $OC_Channel string */
536
-		self::$versionCache['OC_Channel'] = $OC_Channel;
537
-	}
538
-
539
-	/**
540
-	 * generates a path for JS/CSS files. If no application is provided it will create the path for core.
541
-	 *
542
-	 * @param string $application application to get the files from
543
-	 * @param string $directory directory within this application (css, js, vendor, etc)
544
-	 * @param string $file the file inside of the above folder
545
-	 * @return string the path
546
-	 */
547
-	private static function generatePath($application, $directory, $file) {
548
-		if (is_null($file)) {
549
-			$file = $application;
550
-			$application = "";
551
-		}
552
-		if (!empty($application)) {
553
-			return "$application/$directory/$file";
554
-		} else {
555
-			return "$directory/$file";
556
-		}
557
-	}
558
-
559
-	/**
560
-	 * add a javascript file
561
-	 *
562
-	 * @param string $application application id
563
-	 * @param string|null $file filename
564
-	 * @param bool $prepend prepend the Script to the beginning of the list
565
-	 * @return void
566
-	 */
567
-	public static function addScript($application, $file = null, $prepend = false) {
568
-		$path = OC_Util::generatePath($application, 'js', $file);
569
-
570
-		// core js files need separate handling
571
-		if ($application !== 'core' && $file !== null) {
572
-			self::addTranslations ( $application );
573
-		}
574
-		self::addExternalResource($application, $prepend, $path, "script");
575
-	}
576
-
577
-	/**
578
-	 * add a javascript file from the vendor sub folder
579
-	 *
580
-	 * @param string $application application id
581
-	 * @param string|null $file filename
582
-	 * @param bool $prepend prepend the Script to the beginning of the list
583
-	 * @return void
584
-	 */
585
-	public static function addVendorScript($application, $file = null, $prepend = false) {
586
-		$path = OC_Util::generatePath($application, 'vendor', $file);
587
-		self::addExternalResource($application, $prepend, $path, "script");
588
-	}
589
-
590
-	/**
591
-	 * add a translation JS file
592
-	 *
593
-	 * @param string $application application id
594
-	 * @param string|null $languageCode language code, defaults to the current language
595
-	 * @param bool|null $prepend prepend the Script to the beginning of the list
596
-	 */
597
-	public static function addTranslations($application, $languageCode = null, $prepend = false) {
598
-		if (is_null($languageCode)) {
599
-			$languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
600
-		}
601
-		if (!empty($application)) {
602
-			$path = "$application/l10n/$languageCode";
603
-		} else {
604
-			$path = "l10n/$languageCode";
605
-		}
606
-		self::addExternalResource($application, $prepend, $path, "script");
607
-	}
608
-
609
-	/**
610
-	 * add a css file
611
-	 *
612
-	 * @param string $application application id
613
-	 * @param string|null $file filename
614
-	 * @param bool $prepend prepend the Style to the beginning of the list
615
-	 * @return void
616
-	 */
617
-	public static function addStyle($application, $file = null, $prepend = false) {
618
-		$path = OC_Util::generatePath($application, 'css', $file);
619
-		self::addExternalResource($application, $prepend, $path, "style");
620
-	}
621
-
622
-	/**
623
-	 * add a css file from the vendor sub folder
624
-	 *
625
-	 * @param string $application application id
626
-	 * @param string|null $file filename
627
-	 * @param bool $prepend prepend the Style to the beginning of the list
628
-	 * @return void
629
-	 */
630
-	public static function addVendorStyle($application, $file = null, $prepend = false) {
631
-		$path = OC_Util::generatePath($application, 'vendor', $file);
632
-		self::addExternalResource($application, $prepend, $path, "style");
633
-	}
634
-
635
-	/**
636
-	 * add an external resource css/js file
637
-	 *
638
-	 * @param string $application application id
639
-	 * @param bool $prepend prepend the file to the beginning of the list
640
-	 * @param string $path
641
-	 * @param string $type (script or style)
642
-	 * @return void
643
-	 */
644
-	private static function addExternalResource($application, $prepend, $path, $type = "script") {
645
-
646
-		if ($type === "style") {
647
-			if (!in_array($path, self::$styles)) {
648
-				if ($prepend === true) {
649
-					array_unshift ( self::$styles, $path );
650
-				} else {
651
-					self::$styles[] = $path;
652
-				}
653
-			}
654
-		} elseif ($type === "script") {
655
-			if (!in_array($path, self::$scripts)) {
656
-				if ($prepend === true) {
657
-					array_unshift ( self::$scripts, $path );
658
-				} else {
659
-					self::$scripts [] = $path;
660
-				}
661
-			}
662
-		}
663
-	}
664
-
665
-	/**
666
-	 * Add a custom element to the header
667
-	 * If $text is null then the element will be written as empty element.
668
-	 * So use "" to get a closing tag.
669
-	 * @param string $tag tag name of the element
670
-	 * @param array $attributes array of attributes for the element
671
-	 * @param string $text the text content for the element
672
-	 */
673
-	public static function addHeader($tag, $attributes, $text=null) {
674
-		self::$headers[] = array(
675
-			'tag' => $tag,
676
-			'attributes' => $attributes,
677
-			'text' => $text
678
-		);
679
-	}
680
-
681
-	/**
682
-	 * formats a timestamp in the "right" way
683
-	 *
684
-	 * @param int $timestamp
685
-	 * @param bool $dateOnly option to omit time from the result
686
-	 * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to
687
-	 * @return string timestamp
688
-	 *
689
-	 * @deprecated Use \OC::$server->query('DateTimeFormatter') instead
690
-	 */
691
-	public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) {
692
-		if ($timeZone !== null && !$timeZone instanceof \DateTimeZone) {
693
-			$timeZone = new \DateTimeZone($timeZone);
694
-		}
695
-
696
-		/** @var \OC\DateTimeFormatter $formatter */
697
-		$formatter = \OC::$server->query('DateTimeFormatter');
698
-		if ($dateOnly) {
699
-			return $formatter->formatDate($timestamp, 'long', $timeZone);
700
-		}
701
-		return $formatter->formatDateTime($timestamp, 'long', 'long', $timeZone);
702
-	}
703
-
704
-	/**
705
-	 * check if the current server configuration is suitable for ownCloud
706
-	 *
707
-	 * @param \OC\SystemConfig $config
708
-	 * @return array arrays with error messages and hints
709
-	 */
710
-	public static function checkServer(\OC\SystemConfig $config) {
711
-		$l = \OC::$server->getL10N('lib');
712
-		$errors = array();
713
-		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
714
-
715
-		if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
716
-			// this check needs to be done every time
717
-			$errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
718
-		}
719
-
720
-		// Assume that if checkServer() succeeded before in this session, then all is fine.
721
-		if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
722
-			return $errors;
723
-		}
724
-
725
-		$webServerRestart = false;
726
-		$setup = new \OC\Setup(
727
-			$config,
728
-			\OC::$server->getIniWrapper(),
729
-			\OC::$server->getL10N('lib'),
730
-			\OC::$server->query(\OCP\Defaults::class),
731
-			\OC::$server->getLogger(),
732
-			\OC::$server->getSecureRandom(),
733
-			\OC::$server->query(\OC\Installer::class)
734
-		);
735
-
736
-		$urlGenerator = \OC::$server->getURLGenerator();
737
-
738
-		$availableDatabases = $setup->getSupportedDatabases();
739
-		if (empty($availableDatabases)) {
740
-			$errors[] = array(
741
-				'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
742
-				'hint' => '' //TODO: sane hint
743
-			);
744
-			$webServerRestart = true;
745
-		}
746
-
747
-		// Check if config folder is writable.
748
-		if(!OC_Helper::isReadOnlyConfigEnabled()) {
749
-			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
750
-				$errors[] = array(
751
-					'error' => $l->t('Cannot write into "config" directory'),
752
-					'hint' => $l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
753
-						[$urlGenerator->linkToDocs('admin-dir_permissions')])
754
-				);
755
-			}
756
-		}
757
-
758
-		// Check if there is a writable install folder.
759
-		if ($config->getValue('appstoreenabled', true)) {
760
-			if (OC_App::getInstallPath() === null
761
-				|| !is_writable(OC_App::getInstallPath())
762
-				|| !is_readable(OC_App::getInstallPath())
763
-			) {
764
-				$errors[] = array(
765
-					'error' => $l->t('Cannot write into "apps" directory'),
766
-					'hint' => $l->t('This can usually be fixed by giving the webserver write access to the apps directory'
767
-						. ' or disabling the appstore in the config file. See %s',
768
-						[$urlGenerator->linkToDocs('admin-dir_permissions')])
769
-				);
770
-			}
771
-		}
772
-		// Create root dir.
773
-		if ($config->getValue('installed', false)) {
774
-			if (!is_dir($CONFIG_DATADIRECTORY)) {
775
-				$success = @mkdir($CONFIG_DATADIRECTORY);
776
-				if ($success) {
777
-					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
778
-				} else {
779
-					$errors[] = [
780
-						'error' => $l->t('Cannot create "data" directory'),
781
-						'hint' => $l->t('This can usually be fixed by giving the webserver write access to the root directory. See %s',
782
-							[$urlGenerator->linkToDocs('admin-dir_permissions')])
783
-					];
784
-				}
785
-			} else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
786
-				//common hint for all file permissions error messages
787
-				$permissionsHint = $l->t('Permissions can usually be fixed by giving the webserver write access to the root directory. See %s.',
788
-					[$urlGenerator->linkToDocs('admin-dir_permissions')]);
789
-				$errors[] = [
790
-					'error' => 'Your data directory is not writable',
791
-					'hint' => $permissionsHint
792
-				];
793
-			} else {
794
-				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
795
-			}
796
-		}
797
-
798
-		if (!OC_Util::isSetLocaleWorking()) {
799
-			$errors[] = array(
800
-				'error' => $l->t('Setting locale to %s failed',
801
-					array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
802
-						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')),
803
-				'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
804
-			);
805
-		}
806
-
807
-		// Contains the dependencies that should be checked against
808
-		// classes = class_exists
809
-		// functions = function_exists
810
-		// defined = defined
811
-		// ini = ini_get
812
-		// If the dependency is not found the missing module name is shown to the EndUser
813
-		// When adding new checks always verify that they pass on Travis as well
814
-		// for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
815
-		$dependencies = array(
816
-			'classes' => array(
817
-				'ZipArchive' => 'zip',
818
-				'DOMDocument' => 'dom',
819
-				'XMLWriter' => 'XMLWriter',
820
-				'XMLReader' => 'XMLReader',
821
-			),
822
-			'functions' => [
823
-				'xml_parser_create' => 'libxml',
824
-				'mb_strcut' => 'mb multibyte',
825
-				'ctype_digit' => 'ctype',
826
-				'json_encode' => 'JSON',
827
-				'gd_info' => 'GD',
828
-				'gzencode' => 'zlib',
829
-				'iconv' => 'iconv',
830
-				'simplexml_load_string' => 'SimpleXML',
831
-				'hash' => 'HASH Message Digest Framework',
832
-				'curl_init' => 'cURL',
833
-				'openssl_verify' => 'OpenSSL',
834
-			],
835
-			'defined' => array(
836
-				'PDO::ATTR_DRIVER_NAME' => 'PDO'
837
-			),
838
-			'ini' => [
839
-				'default_charset' => 'UTF-8',
840
-			],
841
-		);
842
-		$missingDependencies = array();
843
-		$invalidIniSettings = [];
844
-		$moduleHint = $l->t('Please ask your server administrator to install the module.');
845
-
846
-		/**
847
-		 * FIXME: The dependency check does not work properly on HHVM on the moment
848
-		 *        and prevents installation. Once HHVM is more compatible with our
849
-		 *        approach to check for these values we should re-enable those
850
-		 *        checks.
851
-		 */
852
-		$iniWrapper = \OC::$server->getIniWrapper();
853
-		if (!self::runningOnHhvm()) {
854
-			foreach ($dependencies['classes'] as $class => $module) {
855
-				if (!class_exists($class)) {
856
-					$missingDependencies[] = $module;
857
-				}
858
-			}
859
-			foreach ($dependencies['functions'] as $function => $module) {
860
-				if (!function_exists($function)) {
861
-					$missingDependencies[] = $module;
862
-				}
863
-			}
864
-			foreach ($dependencies['defined'] as $defined => $module) {
865
-				if (!defined($defined)) {
866
-					$missingDependencies[] = $module;
867
-				}
868
-			}
869
-			foreach ($dependencies['ini'] as $setting => $expected) {
870
-				if (is_bool($expected)) {
871
-					if ($iniWrapper->getBool($setting) !== $expected) {
872
-						$invalidIniSettings[] = [$setting, $expected];
873
-					}
874
-				}
875
-				if (is_int($expected)) {
876
-					if ($iniWrapper->getNumeric($setting) !== $expected) {
877
-						$invalidIniSettings[] = [$setting, $expected];
878
-					}
879
-				}
880
-				if (is_string($expected)) {
881
-					if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
882
-						$invalidIniSettings[] = [$setting, $expected];
883
-					}
884
-				}
885
-			}
886
-		}
887
-
888
-		foreach($missingDependencies as $missingDependency) {
889
-			$errors[] = array(
890
-				'error' => $l->t('PHP module %s not installed.', array($missingDependency)),
891
-				'hint' => $moduleHint
892
-			);
893
-			$webServerRestart = true;
894
-		}
895
-		foreach($invalidIniSettings as $setting) {
896
-			if(is_bool($setting[1])) {
897
-				$setting[1] = ($setting[1]) ? 'on' : 'off';
898
-			}
899
-			$errors[] = [
900
-				'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
901
-				'hint' =>  $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
902
-			];
903
-			$webServerRestart = true;
904
-		}
905
-
906
-		/**
907
-		 * The mbstring.func_overload check can only be performed if the mbstring
908
-		 * module is installed as it will return null if the checking setting is
909
-		 * not available and thus a check on the boolean value fails.
910
-		 *
911
-		 * TODO: Should probably be implemented in the above generic dependency
912
-		 *       check somehow in the long-term.
913
-		 */
914
-		if($iniWrapper->getBool('mbstring.func_overload') !== null &&
915
-			$iniWrapper->getBool('mbstring.func_overload') === true) {
916
-			$errors[] = array(
917
-				'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
918
-				'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini')
919
-			);
920
-		}
921
-
922
-		if(function_exists('xml_parser_create') &&
923
-			LIBXML_LOADED_VERSION < 20700 ) {
924
-			$version = LIBXML_LOADED_VERSION;
925
-			$major = floor($version/10000);
926
-			$version -= ($major * 10000);
927
-			$minor = floor($version/100);
928
-			$version -= ($minor * 100);
929
-			$patch = $version;
930
-			$errors[] = array(
931
-				'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
932
-				'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
933
-			);
934
-		}
935
-
936
-		if (!self::isAnnotationsWorking()) {
937
-			$errors[] = array(
938
-				'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
939
-				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
940
-			);
941
-		}
942
-
943
-		if (!\OC::$CLI && $webServerRestart) {
944
-			$errors[] = array(
945
-				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
946
-				'hint' => $l->t('Please ask your server administrator to restart the web server.')
947
-			);
948
-		}
949
-
950
-		$errors = array_merge($errors, self::checkDatabaseVersion());
951
-
952
-		// Cache the result of this function
953
-		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
954
-
955
-		return $errors;
956
-	}
957
-
958
-	/**
959
-	 * Check the database version
960
-	 *
961
-	 * @return array errors array
962
-	 */
963
-	public static function checkDatabaseVersion() {
964
-		$l = \OC::$server->getL10N('lib');
965
-		$errors = array();
966
-		$dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
967
-		if ($dbType === 'pgsql') {
968
-			// check PostgreSQL version
969
-			try {
970
-				$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
971
-				$data = $result->fetchRow();
972
-				if (isset($data['server_version'])) {
973
-					$version = $data['server_version'];
974
-					if (version_compare($version, '9.0.0', '<')) {
975
-						$errors[] = array(
976
-							'error' => $l->t('PostgreSQL >= 9 required'),
977
-							'hint' => $l->t('Please upgrade your database version')
978
-						);
979
-					}
980
-				}
981
-			} catch (\Doctrine\DBAL\DBALException $e) {
982
-				$logger = \OC::$server->getLogger();
983
-				$logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
984
-				$logger->logException($e);
985
-			}
986
-		}
987
-		return $errors;
988
-	}
989
-
990
-	/**
991
-	 * Check for correct file permissions of data directory
992
-	 *
993
-	 * @param string $dataDirectory
994
-	 * @return array arrays with error messages and hints
995
-	 */
996
-	public static function checkDataDirectoryPermissions($dataDirectory) {
997
-		if(\OC::$server->getConfig()->getSystemValue('check_data_directory_permissions', true) === false) {
998
-			return  [];
999
-		}
1000
-		$l = \OC::$server->getL10N('lib');
1001
-		$errors = [];
1002
-		$permissionsModHint = $l->t('Please change the permissions to 0770 so that the directory'
1003
-			. ' cannot be listed by other users.');
1004
-		$perms = substr(decoct(@fileperms($dataDirectory)), -3);
1005
-		if (substr($perms, -1) !== '0') {
1006
-			chmod($dataDirectory, 0770);
1007
-			clearstatcache();
1008
-			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
1009
-			if ($perms[2] !== '0') {
1010
-				$errors[] = [
1011
-					'error' => $l->t('Your data directory is readable by other users'),
1012
-					'hint' => $permissionsModHint
1013
-				];
1014
-			}
1015
-		}
1016
-		return $errors;
1017
-	}
1018
-
1019
-	/**
1020
-	 * Check that the data directory exists and is valid by
1021
-	 * checking the existence of the ".ocdata" file.
1022
-	 *
1023
-	 * @param string $dataDirectory data directory path
1024
-	 * @return array errors found
1025
-	 */
1026
-	public static function checkDataDirectoryValidity($dataDirectory) {
1027
-		$l = \OC::$server->getL10N('lib');
1028
-		$errors = [];
1029
-		if ($dataDirectory[0] !== '/') {
1030
-			$errors[] = [
1031
-				'error' => $l->t('Your data directory must be an absolute path'),
1032
-				'hint' => $l->t('Check the value of "datadirectory" in your configuration')
1033
-			];
1034
-		}
1035
-		if (!file_exists($dataDirectory . '/.ocdata')) {
1036
-			$errors[] = [
1037
-				'error' => $l->t('Your data directory is invalid'),
1038
-				'hint' => $l->t('Ensure there is a file called ".ocdata"' .
1039
-					' in the root of the data directory.')
1040
-			];
1041
-		}
1042
-		return $errors;
1043
-	}
1044
-
1045
-	/**
1046
-	 * Check if the user is logged in, redirects to home if not. With
1047
-	 * redirect URL parameter to the request URI.
1048
-	 *
1049
-	 * @return void
1050
-	 */
1051
-	public static function checkLoggedIn() {
1052
-		// Check if we are a user
1053
-		if (!\OC::$server->getUserSession()->isLoggedIn()) {
1054
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
1055
-						'core.login.showLoginForm',
1056
-						[
1057
-							'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
1058
-						]
1059
-					)
1060
-			);
1061
-			exit();
1062
-		}
1063
-		// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
1064
-		if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
1065
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
1066
-			exit();
1067
-		}
1068
-	}
1069
-
1070
-	/**
1071
-	 * Check if the user is a admin, redirects to home if not
1072
-	 *
1073
-	 * @return void
1074
-	 */
1075
-	public static function checkAdminUser() {
1076
-		OC_Util::checkLoggedIn();
1077
-		if (!OC_User::isAdminUser(OC_User::getUser())) {
1078
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1079
-			exit();
1080
-		}
1081
-	}
1082
-
1083
-	/**
1084
-	 * Check if the user is a subadmin, redirects to home if not
1085
-	 *
1086
-	 * @return null|boolean $groups where the current user is subadmin
1087
-	 */
1088
-	public static function checkSubAdminUser() {
1089
-		OC_Util::checkLoggedIn();
1090
-		$userObject = \OC::$server->getUserSession()->getUser();
1091
-		$isSubAdmin = false;
1092
-		if($userObject !== null) {
1093
-			$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
1094
-		}
1095
-
1096
-		if (!$isSubAdmin) {
1097
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1098
-			exit();
1099
-		}
1100
-		return true;
1101
-	}
1102
-
1103
-	/**
1104
-	 * Returns the URL of the default page
1105
-	 * based on the system configuration and
1106
-	 * the apps visible for the current user
1107
-	 *
1108
-	 * @return string URL
1109
-	 * @suppress PhanDeprecatedFunction
1110
-	 */
1111
-	public static function getDefaultPageUrl() {
1112
-		$urlGenerator = \OC::$server->getURLGenerator();
1113
-		// Deny the redirect if the URL contains a @
1114
-		// This prevents unvalidated redirects like ?redirect_url=:[email protected]
1115
-		if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
1116
-			$location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
1117
-		} else {
1118
-			$defaultPage = \OC::$server->getConfig()->getAppValue('core', 'defaultpage');
1119
-			if ($defaultPage) {
1120
-				$location = $urlGenerator->getAbsoluteURL($defaultPage);
1121
-			} else {
1122
-				$appId = 'files';
1123
-				$config = \OC::$server->getConfig();
1124
-				$defaultApps = explode(',', $config->getSystemValue('defaultapp', 'files'));
1125
-				// find the first app that is enabled for the current user
1126
-				foreach ($defaultApps as $defaultApp) {
1127
-					$defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
1128
-					if (static::getAppManager()->isEnabledForUser($defaultApp)) {
1129
-						$appId = $defaultApp;
1130
-						break;
1131
-					}
1132
-				}
1133
-
1134
-				if($config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true') {
1135
-					$location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1136
-				} else {
1137
-					$location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1138
-				}
1139
-			}
1140
-		}
1141
-		return $location;
1142
-	}
1143
-
1144
-	/**
1145
-	 * Redirect to the user default page
1146
-	 *
1147
-	 * @return void
1148
-	 */
1149
-	public static function redirectToDefaultPage() {
1150
-		$location = self::getDefaultPageUrl();
1151
-		header('Location: ' . $location);
1152
-		exit();
1153
-	}
1154
-
1155
-	/**
1156
-	 * get an id unique for this instance
1157
-	 *
1158
-	 * @return string
1159
-	 */
1160
-	public static function getInstanceId() {
1161
-		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1162
-		if (is_null($id)) {
1163
-			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
1164
-			$id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1165
-			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
1166
-		}
1167
-		return $id;
1168
-	}
1169
-
1170
-	/**
1171
-	 * Public function to sanitize HTML
1172
-	 *
1173
-	 * This function is used to sanitize HTML and should be applied on any
1174
-	 * string or array of strings before displaying it on a web page.
1175
-	 *
1176
-	 * @param string|array $value
1177
-	 * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1178
-	 */
1179
-	public static function sanitizeHTML($value) {
1180
-		if (is_array($value)) {
1181
-			$value = array_map(function($value) {
1182
-				return self::sanitizeHTML($value);
1183
-			}, $value);
1184
-		} else {
1185
-			// Specify encoding for PHP<5.4
1186
-			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1187
-		}
1188
-		return $value;
1189
-	}
1190
-
1191
-	/**
1192
-	 * Public function to encode url parameters
1193
-	 *
1194
-	 * This function is used to encode path to file before output.
1195
-	 * Encoding is done according to RFC 3986 with one exception:
1196
-	 * Character '/' is preserved as is.
1197
-	 *
1198
-	 * @param string $component part of URI to encode
1199
-	 * @return string
1200
-	 */
1201
-	public static function encodePath($component) {
1202
-		$encoded = rawurlencode($component);
1203
-		$encoded = str_replace('%2F', '/', $encoded);
1204
-		return $encoded;
1205
-	}
1206
-
1207
-
1208
-	public function createHtaccessTestFile(\OCP\IConfig $config) {
1209
-		// php dev server does not support htaccess
1210
-		if (php_sapi_name() === 'cli-server') {
1211
-			return false;
1212
-		}
1213
-
1214
-		// testdata
1215
-		$fileName = '/htaccesstest.txt';
1216
-		$testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1217
-
1218
-		// creating a test file
1219
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1220
-
1221
-		if (file_exists($testFile)) {// already running this test, possible recursive call
1222
-			return false;
1223
-		}
1224
-
1225
-		$fp = @fopen($testFile, 'w');
1226
-		if (!$fp) {
1227
-			throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1228
-				'Make sure it is possible for the webserver to write to ' . $testFile);
1229
-		}
1230
-		fwrite($fp, $testContent);
1231
-		fclose($fp);
1232
-
1233
-		return $testContent;
1234
-	}
1235
-
1236
-	/**
1237
-	 * Check if the .htaccess file is working
1238
-	 * @param \OCP\IConfig $config
1239
-	 * @return bool
1240
-	 * @throws Exception
1241
-	 * @throws \OC\HintException If the test file can't get written.
1242
-	 */
1243
-	public function isHtaccessWorking(\OCP\IConfig $config) {
1244
-
1245
-		if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
1246
-			return true;
1247
-		}
1248
-
1249
-		$testContent = $this->createHtaccessTestFile($config);
1250
-		if ($testContent === false) {
1251
-			return false;
1252
-		}
1253
-
1254
-		$fileName = '/htaccesstest.txt';
1255
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1256
-
1257
-		// accessing the file via http
1258
-		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1259
-		try {
1260
-			$content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1261
-		} catch (\Exception $e) {
1262
-			$content = false;
1263
-		}
1264
-
1265
-		// cleanup
1266
-		@unlink($testFile);
1267
-
1268
-		/*
68
+    public static $scripts = array();
69
+    public static $styles = array();
70
+    public static $headers = array();
71
+    private static $rootMounted = false;
72
+    private static $fsSetup = false;
73
+
74
+    /** @var array Local cache of version.php */
75
+    private static $versionCache = null;
76
+
77
+    protected static function getAppManager() {
78
+        return \OC::$server->getAppManager();
79
+    }
80
+
81
+    private static function initLocalStorageRootFS() {
82
+        // mount local file backend as root
83
+        $configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
84
+        //first set up the local "root" storage
85
+        \OC\Files\Filesystem::initMountManager();
86
+        if (!self::$rootMounted) {
87
+            \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir' => $configDataDirectory), '/');
88
+            self::$rootMounted = true;
89
+        }
90
+    }
91
+
92
+    /**
93
+     * mounting an object storage as the root fs will in essence remove the
94
+     * necessity of a data folder being present.
95
+     * TODO make home storage aware of this and use the object storage instead of local disk access
96
+     *
97
+     * @param array $config containing 'class' and optional 'arguments'
98
+     * @suppress PhanDeprecatedFunction
99
+     */
100
+    private static function initObjectStoreRootFS($config) {
101
+        // check misconfiguration
102
+        if (empty($config['class'])) {
103
+            \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
104
+        }
105
+        if (!isset($config['arguments'])) {
106
+            $config['arguments'] = array();
107
+        }
108
+
109
+        // instantiate object store implementation
110
+        $name = $config['class'];
111
+        if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
112
+            $segments = explode('\\', $name);
113
+            OC_App::loadApp(strtolower($segments[1]));
114
+        }
115
+        $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
116
+        // mount with plain / root object store implementation
117
+        $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
118
+
119
+        // mount object storage as root
120
+        \OC\Files\Filesystem::initMountManager();
121
+        if (!self::$rootMounted) {
122
+            \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
123
+            self::$rootMounted = true;
124
+        }
125
+    }
126
+
127
+    /**
128
+     * mounting an object storage as the root fs will in essence remove the
129
+     * necessity of a data folder being present.
130
+     *
131
+     * @param array $config containing 'class' and optional 'arguments'
132
+     * @suppress PhanDeprecatedFunction
133
+     */
134
+    private static function initObjectStoreMultibucketRootFS($config) {
135
+        // check misconfiguration
136
+        if (empty($config['class'])) {
137
+            \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
138
+        }
139
+        if (!isset($config['arguments'])) {
140
+            $config['arguments'] = array();
141
+        }
142
+
143
+        // instantiate object store implementation
144
+        $name = $config['class'];
145
+        if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
146
+            $segments = explode('\\', $name);
147
+            OC_App::loadApp(strtolower($segments[1]));
148
+        }
149
+
150
+        if (!isset($config['arguments']['bucket'])) {
151
+            $config['arguments']['bucket'] = '';
152
+        }
153
+        // put the root FS always in first bucket for multibucket configuration
154
+        $config['arguments']['bucket'] .= '0';
155
+
156
+        $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
157
+        // mount with plain / root object store implementation
158
+        $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
159
+
160
+        // mount object storage as root
161
+        \OC\Files\Filesystem::initMountManager();
162
+        if (!self::$rootMounted) {
163
+            \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
164
+            self::$rootMounted = true;
165
+        }
166
+    }
167
+
168
+    /**
169
+     * Can be set up
170
+     *
171
+     * @param string $user
172
+     * @return boolean
173
+     * @description configure the initial filesystem based on the configuration
174
+     * @suppress PhanDeprecatedFunction
175
+     * @suppress PhanAccessMethodInternal
176
+     */
177
+    public static function setupFS($user = '') {
178
+        //setting up the filesystem twice can only lead to trouble
179
+        if (self::$fsSetup) {
180
+            return false;
181
+        }
182
+
183
+        \OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
184
+
185
+        // If we are not forced to load a specific user we load the one that is logged in
186
+        if ($user === null) {
187
+            $user = '';
188
+        } else if ($user == "" && \OC::$server->getUserSession()->isLoggedIn()) {
189
+            $user = OC_User::getUser();
190
+        }
191
+
192
+        // load all filesystem apps before, so no setup-hook gets lost
193
+        OC_App::loadApps(array('filesystem'));
194
+
195
+        // the filesystem will finish when $user is not empty,
196
+        // mark fs setup here to avoid doing the setup from loading
197
+        // OC_Filesystem
198
+        if ($user != '') {
199
+            self::$fsSetup = true;
200
+        }
201
+
202
+        \OC\Files\Filesystem::initMountManager();
203
+
204
+        \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
205
+        \OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
206
+            if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
207
+                /** @var \OC\Files\Storage\Common $storage */
208
+                $storage->setMountOptions($mount->getOptions());
209
+            }
210
+            return $storage;
211
+        });
212
+
213
+        \OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) {
214
+            if (!$mount->getOption('enable_sharing', true)) {
215
+                return new \OC\Files\Storage\Wrapper\PermissionsMask([
216
+                    'storage' => $storage,
217
+                    'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
218
+                ]);
219
+            }
220
+            return $storage;
221
+        });
222
+
223
+        // install storage availability wrapper, before most other wrappers
224
+        \OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) {
225
+            if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
226
+                return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
227
+            }
228
+            return $storage;
229
+        });
230
+
231
+        \OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
232
+            if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
233
+                return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
234
+            }
235
+            return $storage;
236
+        });
237
+
238
+        \OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
239
+            // set up quota for home storages, even for other users
240
+            // which can happen when using sharing
241
+
242
+            /**
243
+             * @var \OC\Files\Storage\Storage $storage
244
+             */
245
+            if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
246
+                || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
247
+            ) {
248
+                /** @var \OC\Files\Storage\Home $storage */
249
+                if (is_object($storage->getUser())) {
250
+                    $user = $storage->getUser()->getUID();
251
+                    $quota = OC_Util::getUserQuota($user);
252
+                    if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
253
+                        return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files'));
254
+                    }
255
+                }
256
+            }
257
+
258
+            return $storage;
259
+        });
260
+
261
+        OC_Hook::emit('OC_Filesystem', 'preSetup', array('user' => $user));
262
+        \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(true);
263
+
264
+        //check if we are using an object storage
265
+        $objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
266
+        $objectStoreMultibucket = \OC::$server->getSystemConfig()->getValue('objectstore_multibucket', null);
267
+
268
+        // use the same order as in ObjectHomeMountProvider
269
+        if (isset($objectStoreMultibucket)) {
270
+            self::initObjectStoreMultibucketRootFS($objectStoreMultibucket);
271
+        } elseif (isset($objectStore)) {
272
+            self::initObjectStoreRootFS($objectStore);
273
+        } else {
274
+            self::initLocalStorageRootFS();
275
+        }
276
+
277
+        if ($user != '' && !\OC::$server->getUserManager()->userExists($user)) {
278
+            \OC::$server->getEventLogger()->end('setup_fs');
279
+            return false;
280
+        }
281
+
282
+        //if we aren't logged in, there is no use to set up the filesystem
283
+        if ($user != "") {
284
+
285
+            $userDir = '/' . $user . '/files';
286
+
287
+            //jail the user into his "home" directory
288
+            \OC\Files\Filesystem::init($user, $userDir);
289
+
290
+            OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir));
291
+        }
292
+        \OC::$server->getEventLogger()->end('setup_fs');
293
+        return true;
294
+    }
295
+
296
+    /**
297
+     * check if a password is required for each public link
298
+     *
299
+     * @return boolean
300
+     * @suppress PhanDeprecatedFunction
301
+     */
302
+    public static function isPublicLinkPasswordRequired() {
303
+        $enforcePassword = \OC::$server->getConfig()->getAppValue('core', 'shareapi_enforce_links_password', 'no');
304
+        return $enforcePassword === 'yes';
305
+    }
306
+
307
+    /**
308
+     * check if sharing is disabled for the current user
309
+     * @param IConfig $config
310
+     * @param IGroupManager $groupManager
311
+     * @param IUser|null $user
312
+     * @return bool
313
+     */
314
+    public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
315
+        if ($config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
316
+            $groupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
317
+            $excludedGroups = json_decode($groupsList);
318
+            if (is_null($excludedGroups)) {
319
+                $excludedGroups = explode(',', $groupsList);
320
+                $newValue = json_encode($excludedGroups);
321
+                $config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
322
+            }
323
+            $usersGroups = $groupManager->getUserGroupIds($user);
324
+            if (!empty($usersGroups)) {
325
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
326
+                // if the user is only in groups which are disabled for sharing then
327
+                // sharing is also disabled for the user
328
+                if (empty($remainingGroups)) {
329
+                    return true;
330
+                }
331
+            }
332
+        }
333
+        return false;
334
+    }
335
+
336
+    /**
337
+     * check if share API enforces a default expire date
338
+     *
339
+     * @return boolean
340
+     * @suppress PhanDeprecatedFunction
341
+     */
342
+    public static function isDefaultExpireDateEnforced() {
343
+        $isDefaultExpireDateEnabled = \OC::$server->getConfig()->getAppValue('core', 'shareapi_default_expire_date', 'no');
344
+        $enforceDefaultExpireDate = false;
345
+        if ($isDefaultExpireDateEnabled === 'yes') {
346
+            $value = \OC::$server->getConfig()->getAppValue('core', 'shareapi_enforce_expire_date', 'no');
347
+            $enforceDefaultExpireDate = $value === 'yes';
348
+        }
349
+
350
+        return $enforceDefaultExpireDate;
351
+    }
352
+
353
+    /**
354
+     * Get the quota of a user
355
+     *
356
+     * @param string $userId
357
+     * @return float Quota bytes
358
+     */
359
+    public static function getUserQuota($userId) {
360
+        $user = \OC::$server->getUserManager()->get($userId);
361
+        if (is_null($user)) {
362
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
363
+        }
364
+        $userQuota = $user->getQuota();
365
+        if($userQuota === 'none') {
366
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
367
+        }
368
+        return OC_Helper::computerFileSize($userQuota);
369
+    }
370
+
371
+    /**
372
+     * copies the skeleton to the users /files
373
+     *
374
+     * @param String $userId
375
+     * @param \OCP\Files\Folder $userDirectory
376
+     * @throws \RuntimeException
377
+     * @suppress PhanDeprecatedFunction
378
+     */
379
+    public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
380
+
381
+        $plainSkeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
382
+        $userLang = \OC::$server->getL10NFactory()->findLanguage();
383
+        $skeletonDirectory = str_replace('{lang}', $userLang, $plainSkeletonDirectory);
384
+
385
+        if (!file_exists($skeletonDirectory)) {
386
+            $dialectStart = strpos($userLang, '_');
387
+            if ($dialectStart !== false) {
388
+                $skeletonDirectory = str_replace('{lang}', substr($userLang, 0, $dialectStart), $plainSkeletonDirectory);
389
+            }
390
+            if ($dialectStart === false || !file_exists($skeletonDirectory)) {
391
+                $skeletonDirectory = str_replace('{lang}', 'default', $plainSkeletonDirectory);
392
+            }
393
+            if (!file_exists($skeletonDirectory)) {
394
+                $skeletonDirectory = '';
395
+            }
396
+        }
397
+
398
+        $instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
399
+
400
+        if ($instanceId === null) {
401
+            throw new \RuntimeException('no instance id!');
402
+        }
403
+        $appdata = 'appdata_' . $instanceId;
404
+        if ($userId === $appdata) {
405
+            throw new \RuntimeException('username is reserved name: ' . $appdata);
406
+        }
407
+
408
+        if (!empty($skeletonDirectory)) {
409
+            \OCP\Util::writeLog(
410
+                'files_skeleton',
411
+                'copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'),
412
+                \OCP\Util::DEBUG
413
+            );
414
+            self::copyr($skeletonDirectory, $userDirectory);
415
+            // update the file cache
416
+            $userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
417
+        }
418
+    }
419
+
420
+    /**
421
+     * copies a directory recursively by using streams
422
+     *
423
+     * @param string $source
424
+     * @param \OCP\Files\Folder $target
425
+     * @return void
426
+     */
427
+    public static function copyr($source, \OCP\Files\Folder $target) {
428
+        $logger = \OC::$server->getLogger();
429
+
430
+        // Verify if folder exists
431
+        $dir = opendir($source);
432
+        if($dir === false) {
433
+            $logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
434
+            return;
435
+        }
436
+
437
+        // Copy the files
438
+        while (false !== ($file = readdir($dir))) {
439
+            if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
440
+                if (is_dir($source . '/' . $file)) {
441
+                    $child = $target->newFolder($file);
442
+                    self::copyr($source . '/' . $file, $child);
443
+                } else {
444
+                    $child = $target->newFile($file);
445
+                    $sourceStream = fopen($source . '/' . $file, 'r');
446
+                    if($sourceStream === false) {
447
+                        $logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
448
+                        closedir($dir);
449
+                        return;
450
+                    }
451
+                    stream_copy_to_stream($sourceStream, $child->fopen('w'));
452
+                }
453
+            }
454
+        }
455
+        closedir($dir);
456
+    }
457
+
458
+    /**
459
+     * @return void
460
+     * @suppress PhanUndeclaredMethod
461
+     */
462
+    public static function tearDownFS() {
463
+        \OC\Files\Filesystem::tearDown();
464
+        \OC::$server->getRootFolder()->clearCache();
465
+        self::$fsSetup = false;
466
+        self::$rootMounted = false;
467
+    }
468
+
469
+    /**
470
+     * get the current installed version of ownCloud
471
+     *
472
+     * @return array
473
+     */
474
+    public static function getVersion() {
475
+        OC_Util::loadVersion();
476
+        return self::$versionCache['OC_Version'];
477
+    }
478
+
479
+    /**
480
+     * get the current installed version string of ownCloud
481
+     *
482
+     * @return string
483
+     */
484
+    public static function getVersionString() {
485
+        OC_Util::loadVersion();
486
+        return self::$versionCache['OC_VersionString'];
487
+    }
488
+
489
+    /**
490
+     * @deprecated the value is of no use anymore
491
+     * @return string
492
+     */
493
+    public static function getEditionString() {
494
+        return '';
495
+    }
496
+
497
+    /**
498
+     * @description get the update channel of the current installed of ownCloud.
499
+     * @return string
500
+     */
501
+    public static function getChannel() {
502
+        OC_Util::loadVersion();
503
+        return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
504
+    }
505
+
506
+    /**
507
+     * @description get the build number of the current installed of ownCloud.
508
+     * @return string
509
+     */
510
+    public static function getBuild() {
511
+        OC_Util::loadVersion();
512
+        return self::$versionCache['OC_Build'];
513
+    }
514
+
515
+    /**
516
+     * @description load the version.php into the session as cache
517
+     * @suppress PhanUndeclaredVariable
518
+     */
519
+    private static function loadVersion() {
520
+        if (self::$versionCache !== null) {
521
+            return;
522
+        }
523
+
524
+        $timestamp = filemtime(OC::$SERVERROOT . '/version.php');
525
+        require OC::$SERVERROOT . '/version.php';
526
+        /** @var $timestamp int */
527
+        self::$versionCache['OC_Version_Timestamp'] = $timestamp;
528
+        /** @var $OC_Version string */
529
+        self::$versionCache['OC_Version'] = $OC_Version;
530
+        /** @var $OC_VersionString string */
531
+        self::$versionCache['OC_VersionString'] = $OC_VersionString;
532
+        /** @var $OC_Build string */
533
+        self::$versionCache['OC_Build'] = $OC_Build;
534
+
535
+        /** @var $OC_Channel string */
536
+        self::$versionCache['OC_Channel'] = $OC_Channel;
537
+    }
538
+
539
+    /**
540
+     * generates a path for JS/CSS files. If no application is provided it will create the path for core.
541
+     *
542
+     * @param string $application application to get the files from
543
+     * @param string $directory directory within this application (css, js, vendor, etc)
544
+     * @param string $file the file inside of the above folder
545
+     * @return string the path
546
+     */
547
+    private static function generatePath($application, $directory, $file) {
548
+        if (is_null($file)) {
549
+            $file = $application;
550
+            $application = "";
551
+        }
552
+        if (!empty($application)) {
553
+            return "$application/$directory/$file";
554
+        } else {
555
+            return "$directory/$file";
556
+        }
557
+    }
558
+
559
+    /**
560
+     * add a javascript file
561
+     *
562
+     * @param string $application application id
563
+     * @param string|null $file filename
564
+     * @param bool $prepend prepend the Script to the beginning of the list
565
+     * @return void
566
+     */
567
+    public static function addScript($application, $file = null, $prepend = false) {
568
+        $path = OC_Util::generatePath($application, 'js', $file);
569
+
570
+        // core js files need separate handling
571
+        if ($application !== 'core' && $file !== null) {
572
+            self::addTranslations ( $application );
573
+        }
574
+        self::addExternalResource($application, $prepend, $path, "script");
575
+    }
576
+
577
+    /**
578
+     * add a javascript file from the vendor sub folder
579
+     *
580
+     * @param string $application application id
581
+     * @param string|null $file filename
582
+     * @param bool $prepend prepend the Script to the beginning of the list
583
+     * @return void
584
+     */
585
+    public static function addVendorScript($application, $file = null, $prepend = false) {
586
+        $path = OC_Util::generatePath($application, 'vendor', $file);
587
+        self::addExternalResource($application, $prepend, $path, "script");
588
+    }
589
+
590
+    /**
591
+     * add a translation JS file
592
+     *
593
+     * @param string $application application id
594
+     * @param string|null $languageCode language code, defaults to the current language
595
+     * @param bool|null $prepend prepend the Script to the beginning of the list
596
+     */
597
+    public static function addTranslations($application, $languageCode = null, $prepend = false) {
598
+        if (is_null($languageCode)) {
599
+            $languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
600
+        }
601
+        if (!empty($application)) {
602
+            $path = "$application/l10n/$languageCode";
603
+        } else {
604
+            $path = "l10n/$languageCode";
605
+        }
606
+        self::addExternalResource($application, $prepend, $path, "script");
607
+    }
608
+
609
+    /**
610
+     * add a css file
611
+     *
612
+     * @param string $application application id
613
+     * @param string|null $file filename
614
+     * @param bool $prepend prepend the Style to the beginning of the list
615
+     * @return void
616
+     */
617
+    public static function addStyle($application, $file = null, $prepend = false) {
618
+        $path = OC_Util::generatePath($application, 'css', $file);
619
+        self::addExternalResource($application, $prepend, $path, "style");
620
+    }
621
+
622
+    /**
623
+     * add a css file from the vendor sub folder
624
+     *
625
+     * @param string $application application id
626
+     * @param string|null $file filename
627
+     * @param bool $prepend prepend the Style to the beginning of the list
628
+     * @return void
629
+     */
630
+    public static function addVendorStyle($application, $file = null, $prepend = false) {
631
+        $path = OC_Util::generatePath($application, 'vendor', $file);
632
+        self::addExternalResource($application, $prepend, $path, "style");
633
+    }
634
+
635
+    /**
636
+     * add an external resource css/js file
637
+     *
638
+     * @param string $application application id
639
+     * @param bool $prepend prepend the file to the beginning of the list
640
+     * @param string $path
641
+     * @param string $type (script or style)
642
+     * @return void
643
+     */
644
+    private static function addExternalResource($application, $prepend, $path, $type = "script") {
645
+
646
+        if ($type === "style") {
647
+            if (!in_array($path, self::$styles)) {
648
+                if ($prepend === true) {
649
+                    array_unshift ( self::$styles, $path );
650
+                } else {
651
+                    self::$styles[] = $path;
652
+                }
653
+            }
654
+        } elseif ($type === "script") {
655
+            if (!in_array($path, self::$scripts)) {
656
+                if ($prepend === true) {
657
+                    array_unshift ( self::$scripts, $path );
658
+                } else {
659
+                    self::$scripts [] = $path;
660
+                }
661
+            }
662
+        }
663
+    }
664
+
665
+    /**
666
+     * Add a custom element to the header
667
+     * If $text is null then the element will be written as empty element.
668
+     * So use "" to get a closing tag.
669
+     * @param string $tag tag name of the element
670
+     * @param array $attributes array of attributes for the element
671
+     * @param string $text the text content for the element
672
+     */
673
+    public static function addHeader($tag, $attributes, $text=null) {
674
+        self::$headers[] = array(
675
+            'tag' => $tag,
676
+            'attributes' => $attributes,
677
+            'text' => $text
678
+        );
679
+    }
680
+
681
+    /**
682
+     * formats a timestamp in the "right" way
683
+     *
684
+     * @param int $timestamp
685
+     * @param bool $dateOnly option to omit time from the result
686
+     * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to
687
+     * @return string timestamp
688
+     *
689
+     * @deprecated Use \OC::$server->query('DateTimeFormatter') instead
690
+     */
691
+    public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) {
692
+        if ($timeZone !== null && !$timeZone instanceof \DateTimeZone) {
693
+            $timeZone = new \DateTimeZone($timeZone);
694
+        }
695
+
696
+        /** @var \OC\DateTimeFormatter $formatter */
697
+        $formatter = \OC::$server->query('DateTimeFormatter');
698
+        if ($dateOnly) {
699
+            return $formatter->formatDate($timestamp, 'long', $timeZone);
700
+        }
701
+        return $formatter->formatDateTime($timestamp, 'long', 'long', $timeZone);
702
+    }
703
+
704
+    /**
705
+     * check if the current server configuration is suitable for ownCloud
706
+     *
707
+     * @param \OC\SystemConfig $config
708
+     * @return array arrays with error messages and hints
709
+     */
710
+    public static function checkServer(\OC\SystemConfig $config) {
711
+        $l = \OC::$server->getL10N('lib');
712
+        $errors = array();
713
+        $CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
714
+
715
+        if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
716
+            // this check needs to be done every time
717
+            $errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
718
+        }
719
+
720
+        // Assume that if checkServer() succeeded before in this session, then all is fine.
721
+        if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
722
+            return $errors;
723
+        }
724
+
725
+        $webServerRestart = false;
726
+        $setup = new \OC\Setup(
727
+            $config,
728
+            \OC::$server->getIniWrapper(),
729
+            \OC::$server->getL10N('lib'),
730
+            \OC::$server->query(\OCP\Defaults::class),
731
+            \OC::$server->getLogger(),
732
+            \OC::$server->getSecureRandom(),
733
+            \OC::$server->query(\OC\Installer::class)
734
+        );
735
+
736
+        $urlGenerator = \OC::$server->getURLGenerator();
737
+
738
+        $availableDatabases = $setup->getSupportedDatabases();
739
+        if (empty($availableDatabases)) {
740
+            $errors[] = array(
741
+                'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
742
+                'hint' => '' //TODO: sane hint
743
+            );
744
+            $webServerRestart = true;
745
+        }
746
+
747
+        // Check if config folder is writable.
748
+        if(!OC_Helper::isReadOnlyConfigEnabled()) {
749
+            if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
750
+                $errors[] = array(
751
+                    'error' => $l->t('Cannot write into "config" directory'),
752
+                    'hint' => $l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
753
+                        [$urlGenerator->linkToDocs('admin-dir_permissions')])
754
+                );
755
+            }
756
+        }
757
+
758
+        // Check if there is a writable install folder.
759
+        if ($config->getValue('appstoreenabled', true)) {
760
+            if (OC_App::getInstallPath() === null
761
+                || !is_writable(OC_App::getInstallPath())
762
+                || !is_readable(OC_App::getInstallPath())
763
+            ) {
764
+                $errors[] = array(
765
+                    'error' => $l->t('Cannot write into "apps" directory'),
766
+                    'hint' => $l->t('This can usually be fixed by giving the webserver write access to the apps directory'
767
+                        . ' or disabling the appstore in the config file. See %s',
768
+                        [$urlGenerator->linkToDocs('admin-dir_permissions')])
769
+                );
770
+            }
771
+        }
772
+        // Create root dir.
773
+        if ($config->getValue('installed', false)) {
774
+            if (!is_dir($CONFIG_DATADIRECTORY)) {
775
+                $success = @mkdir($CONFIG_DATADIRECTORY);
776
+                if ($success) {
777
+                    $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
778
+                } else {
779
+                    $errors[] = [
780
+                        'error' => $l->t('Cannot create "data" directory'),
781
+                        'hint' => $l->t('This can usually be fixed by giving the webserver write access to the root directory. See %s',
782
+                            [$urlGenerator->linkToDocs('admin-dir_permissions')])
783
+                    ];
784
+                }
785
+            } else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
786
+                //common hint for all file permissions error messages
787
+                $permissionsHint = $l->t('Permissions can usually be fixed by giving the webserver write access to the root directory. See %s.',
788
+                    [$urlGenerator->linkToDocs('admin-dir_permissions')]);
789
+                $errors[] = [
790
+                    'error' => 'Your data directory is not writable',
791
+                    'hint' => $permissionsHint
792
+                ];
793
+            } else {
794
+                $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
795
+            }
796
+        }
797
+
798
+        if (!OC_Util::isSetLocaleWorking()) {
799
+            $errors[] = array(
800
+                'error' => $l->t('Setting locale to %s failed',
801
+                    array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
802
+                        . 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')),
803
+                'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
804
+            );
805
+        }
806
+
807
+        // Contains the dependencies that should be checked against
808
+        // classes = class_exists
809
+        // functions = function_exists
810
+        // defined = defined
811
+        // ini = ini_get
812
+        // If the dependency is not found the missing module name is shown to the EndUser
813
+        // When adding new checks always verify that they pass on Travis as well
814
+        // for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
815
+        $dependencies = array(
816
+            'classes' => array(
817
+                'ZipArchive' => 'zip',
818
+                'DOMDocument' => 'dom',
819
+                'XMLWriter' => 'XMLWriter',
820
+                'XMLReader' => 'XMLReader',
821
+            ),
822
+            'functions' => [
823
+                'xml_parser_create' => 'libxml',
824
+                'mb_strcut' => 'mb multibyte',
825
+                'ctype_digit' => 'ctype',
826
+                'json_encode' => 'JSON',
827
+                'gd_info' => 'GD',
828
+                'gzencode' => 'zlib',
829
+                'iconv' => 'iconv',
830
+                'simplexml_load_string' => 'SimpleXML',
831
+                'hash' => 'HASH Message Digest Framework',
832
+                'curl_init' => 'cURL',
833
+                'openssl_verify' => 'OpenSSL',
834
+            ],
835
+            'defined' => array(
836
+                'PDO::ATTR_DRIVER_NAME' => 'PDO'
837
+            ),
838
+            'ini' => [
839
+                'default_charset' => 'UTF-8',
840
+            ],
841
+        );
842
+        $missingDependencies = array();
843
+        $invalidIniSettings = [];
844
+        $moduleHint = $l->t('Please ask your server administrator to install the module.');
845
+
846
+        /**
847
+         * FIXME: The dependency check does not work properly on HHVM on the moment
848
+         *        and prevents installation. Once HHVM is more compatible with our
849
+         *        approach to check for these values we should re-enable those
850
+         *        checks.
851
+         */
852
+        $iniWrapper = \OC::$server->getIniWrapper();
853
+        if (!self::runningOnHhvm()) {
854
+            foreach ($dependencies['classes'] as $class => $module) {
855
+                if (!class_exists($class)) {
856
+                    $missingDependencies[] = $module;
857
+                }
858
+            }
859
+            foreach ($dependencies['functions'] as $function => $module) {
860
+                if (!function_exists($function)) {
861
+                    $missingDependencies[] = $module;
862
+                }
863
+            }
864
+            foreach ($dependencies['defined'] as $defined => $module) {
865
+                if (!defined($defined)) {
866
+                    $missingDependencies[] = $module;
867
+                }
868
+            }
869
+            foreach ($dependencies['ini'] as $setting => $expected) {
870
+                if (is_bool($expected)) {
871
+                    if ($iniWrapper->getBool($setting) !== $expected) {
872
+                        $invalidIniSettings[] = [$setting, $expected];
873
+                    }
874
+                }
875
+                if (is_int($expected)) {
876
+                    if ($iniWrapper->getNumeric($setting) !== $expected) {
877
+                        $invalidIniSettings[] = [$setting, $expected];
878
+                    }
879
+                }
880
+                if (is_string($expected)) {
881
+                    if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
882
+                        $invalidIniSettings[] = [$setting, $expected];
883
+                    }
884
+                }
885
+            }
886
+        }
887
+
888
+        foreach($missingDependencies as $missingDependency) {
889
+            $errors[] = array(
890
+                'error' => $l->t('PHP module %s not installed.', array($missingDependency)),
891
+                'hint' => $moduleHint
892
+            );
893
+            $webServerRestart = true;
894
+        }
895
+        foreach($invalidIniSettings as $setting) {
896
+            if(is_bool($setting[1])) {
897
+                $setting[1] = ($setting[1]) ? 'on' : 'off';
898
+            }
899
+            $errors[] = [
900
+                'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
901
+                'hint' =>  $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
902
+            ];
903
+            $webServerRestart = true;
904
+        }
905
+
906
+        /**
907
+         * The mbstring.func_overload check can only be performed if the mbstring
908
+         * module is installed as it will return null if the checking setting is
909
+         * not available and thus a check on the boolean value fails.
910
+         *
911
+         * TODO: Should probably be implemented in the above generic dependency
912
+         *       check somehow in the long-term.
913
+         */
914
+        if($iniWrapper->getBool('mbstring.func_overload') !== null &&
915
+            $iniWrapper->getBool('mbstring.func_overload') === true) {
916
+            $errors[] = array(
917
+                'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
918
+                'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini')
919
+            );
920
+        }
921
+
922
+        if(function_exists('xml_parser_create') &&
923
+            LIBXML_LOADED_VERSION < 20700 ) {
924
+            $version = LIBXML_LOADED_VERSION;
925
+            $major = floor($version/10000);
926
+            $version -= ($major * 10000);
927
+            $minor = floor($version/100);
928
+            $version -= ($minor * 100);
929
+            $patch = $version;
930
+            $errors[] = array(
931
+                'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
932
+                'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
933
+            );
934
+        }
935
+
936
+        if (!self::isAnnotationsWorking()) {
937
+            $errors[] = array(
938
+                'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
939
+                'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
940
+            );
941
+        }
942
+
943
+        if (!\OC::$CLI && $webServerRestart) {
944
+            $errors[] = array(
945
+                'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
946
+                'hint' => $l->t('Please ask your server administrator to restart the web server.')
947
+            );
948
+        }
949
+
950
+        $errors = array_merge($errors, self::checkDatabaseVersion());
951
+
952
+        // Cache the result of this function
953
+        \OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
954
+
955
+        return $errors;
956
+    }
957
+
958
+    /**
959
+     * Check the database version
960
+     *
961
+     * @return array errors array
962
+     */
963
+    public static function checkDatabaseVersion() {
964
+        $l = \OC::$server->getL10N('lib');
965
+        $errors = array();
966
+        $dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
967
+        if ($dbType === 'pgsql') {
968
+            // check PostgreSQL version
969
+            try {
970
+                $result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
971
+                $data = $result->fetchRow();
972
+                if (isset($data['server_version'])) {
973
+                    $version = $data['server_version'];
974
+                    if (version_compare($version, '9.0.0', '<')) {
975
+                        $errors[] = array(
976
+                            'error' => $l->t('PostgreSQL >= 9 required'),
977
+                            'hint' => $l->t('Please upgrade your database version')
978
+                        );
979
+                    }
980
+                }
981
+            } catch (\Doctrine\DBAL\DBALException $e) {
982
+                $logger = \OC::$server->getLogger();
983
+                $logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
984
+                $logger->logException($e);
985
+            }
986
+        }
987
+        return $errors;
988
+    }
989
+
990
+    /**
991
+     * Check for correct file permissions of data directory
992
+     *
993
+     * @param string $dataDirectory
994
+     * @return array arrays with error messages and hints
995
+     */
996
+    public static function checkDataDirectoryPermissions($dataDirectory) {
997
+        if(\OC::$server->getConfig()->getSystemValue('check_data_directory_permissions', true) === false) {
998
+            return  [];
999
+        }
1000
+        $l = \OC::$server->getL10N('lib');
1001
+        $errors = [];
1002
+        $permissionsModHint = $l->t('Please change the permissions to 0770 so that the directory'
1003
+            . ' cannot be listed by other users.');
1004
+        $perms = substr(decoct(@fileperms($dataDirectory)), -3);
1005
+        if (substr($perms, -1) !== '0') {
1006
+            chmod($dataDirectory, 0770);
1007
+            clearstatcache();
1008
+            $perms = substr(decoct(@fileperms($dataDirectory)), -3);
1009
+            if ($perms[2] !== '0') {
1010
+                $errors[] = [
1011
+                    'error' => $l->t('Your data directory is readable by other users'),
1012
+                    'hint' => $permissionsModHint
1013
+                ];
1014
+            }
1015
+        }
1016
+        return $errors;
1017
+    }
1018
+
1019
+    /**
1020
+     * Check that the data directory exists and is valid by
1021
+     * checking the existence of the ".ocdata" file.
1022
+     *
1023
+     * @param string $dataDirectory data directory path
1024
+     * @return array errors found
1025
+     */
1026
+    public static function checkDataDirectoryValidity($dataDirectory) {
1027
+        $l = \OC::$server->getL10N('lib');
1028
+        $errors = [];
1029
+        if ($dataDirectory[0] !== '/') {
1030
+            $errors[] = [
1031
+                'error' => $l->t('Your data directory must be an absolute path'),
1032
+                'hint' => $l->t('Check the value of "datadirectory" in your configuration')
1033
+            ];
1034
+        }
1035
+        if (!file_exists($dataDirectory . '/.ocdata')) {
1036
+            $errors[] = [
1037
+                'error' => $l->t('Your data directory is invalid'),
1038
+                'hint' => $l->t('Ensure there is a file called ".ocdata"' .
1039
+                    ' in the root of the data directory.')
1040
+            ];
1041
+        }
1042
+        return $errors;
1043
+    }
1044
+
1045
+    /**
1046
+     * Check if the user is logged in, redirects to home if not. With
1047
+     * redirect URL parameter to the request URI.
1048
+     *
1049
+     * @return void
1050
+     */
1051
+    public static function checkLoggedIn() {
1052
+        // Check if we are a user
1053
+        if (!\OC::$server->getUserSession()->isLoggedIn()) {
1054
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
1055
+                        'core.login.showLoginForm',
1056
+                        [
1057
+                            'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
1058
+                        ]
1059
+                    )
1060
+            );
1061
+            exit();
1062
+        }
1063
+        // Redirect to 2FA challenge selection if 2FA challenge was not solved yet
1064
+        if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
1065
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
1066
+            exit();
1067
+        }
1068
+    }
1069
+
1070
+    /**
1071
+     * Check if the user is a admin, redirects to home if not
1072
+     *
1073
+     * @return void
1074
+     */
1075
+    public static function checkAdminUser() {
1076
+        OC_Util::checkLoggedIn();
1077
+        if (!OC_User::isAdminUser(OC_User::getUser())) {
1078
+            header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1079
+            exit();
1080
+        }
1081
+    }
1082
+
1083
+    /**
1084
+     * Check if the user is a subadmin, redirects to home if not
1085
+     *
1086
+     * @return null|boolean $groups where the current user is subadmin
1087
+     */
1088
+    public static function checkSubAdminUser() {
1089
+        OC_Util::checkLoggedIn();
1090
+        $userObject = \OC::$server->getUserSession()->getUser();
1091
+        $isSubAdmin = false;
1092
+        if($userObject !== null) {
1093
+            $isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
1094
+        }
1095
+
1096
+        if (!$isSubAdmin) {
1097
+            header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1098
+            exit();
1099
+        }
1100
+        return true;
1101
+    }
1102
+
1103
+    /**
1104
+     * Returns the URL of the default page
1105
+     * based on the system configuration and
1106
+     * the apps visible for the current user
1107
+     *
1108
+     * @return string URL
1109
+     * @suppress PhanDeprecatedFunction
1110
+     */
1111
+    public static function getDefaultPageUrl() {
1112
+        $urlGenerator = \OC::$server->getURLGenerator();
1113
+        // Deny the redirect if the URL contains a @
1114
+        // This prevents unvalidated redirects like ?redirect_url=:[email protected]
1115
+        if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
1116
+            $location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
1117
+        } else {
1118
+            $defaultPage = \OC::$server->getConfig()->getAppValue('core', 'defaultpage');
1119
+            if ($defaultPage) {
1120
+                $location = $urlGenerator->getAbsoluteURL($defaultPage);
1121
+            } else {
1122
+                $appId = 'files';
1123
+                $config = \OC::$server->getConfig();
1124
+                $defaultApps = explode(',', $config->getSystemValue('defaultapp', 'files'));
1125
+                // find the first app that is enabled for the current user
1126
+                foreach ($defaultApps as $defaultApp) {
1127
+                    $defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
1128
+                    if (static::getAppManager()->isEnabledForUser($defaultApp)) {
1129
+                        $appId = $defaultApp;
1130
+                        break;
1131
+                    }
1132
+                }
1133
+
1134
+                if($config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true') {
1135
+                    $location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1136
+                } else {
1137
+                    $location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1138
+                }
1139
+            }
1140
+        }
1141
+        return $location;
1142
+    }
1143
+
1144
+    /**
1145
+     * Redirect to the user default page
1146
+     *
1147
+     * @return void
1148
+     */
1149
+    public static function redirectToDefaultPage() {
1150
+        $location = self::getDefaultPageUrl();
1151
+        header('Location: ' . $location);
1152
+        exit();
1153
+    }
1154
+
1155
+    /**
1156
+     * get an id unique for this instance
1157
+     *
1158
+     * @return string
1159
+     */
1160
+    public static function getInstanceId() {
1161
+        $id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1162
+        if (is_null($id)) {
1163
+            // We need to guarantee at least one letter in instanceid so it can be used as the session_name
1164
+            $id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1165
+            \OC::$server->getSystemConfig()->setValue('instanceid', $id);
1166
+        }
1167
+        return $id;
1168
+    }
1169
+
1170
+    /**
1171
+     * Public function to sanitize HTML
1172
+     *
1173
+     * This function is used to sanitize HTML and should be applied on any
1174
+     * string or array of strings before displaying it on a web page.
1175
+     *
1176
+     * @param string|array $value
1177
+     * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1178
+     */
1179
+    public static function sanitizeHTML($value) {
1180
+        if (is_array($value)) {
1181
+            $value = array_map(function($value) {
1182
+                return self::sanitizeHTML($value);
1183
+            }, $value);
1184
+        } else {
1185
+            // Specify encoding for PHP<5.4
1186
+            $value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1187
+        }
1188
+        return $value;
1189
+    }
1190
+
1191
+    /**
1192
+     * Public function to encode url parameters
1193
+     *
1194
+     * This function is used to encode path to file before output.
1195
+     * Encoding is done according to RFC 3986 with one exception:
1196
+     * Character '/' is preserved as is.
1197
+     *
1198
+     * @param string $component part of URI to encode
1199
+     * @return string
1200
+     */
1201
+    public static function encodePath($component) {
1202
+        $encoded = rawurlencode($component);
1203
+        $encoded = str_replace('%2F', '/', $encoded);
1204
+        return $encoded;
1205
+    }
1206
+
1207
+
1208
+    public function createHtaccessTestFile(\OCP\IConfig $config) {
1209
+        // php dev server does not support htaccess
1210
+        if (php_sapi_name() === 'cli-server') {
1211
+            return false;
1212
+        }
1213
+
1214
+        // testdata
1215
+        $fileName = '/htaccesstest.txt';
1216
+        $testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1217
+
1218
+        // creating a test file
1219
+        $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1220
+
1221
+        if (file_exists($testFile)) {// already running this test, possible recursive call
1222
+            return false;
1223
+        }
1224
+
1225
+        $fp = @fopen($testFile, 'w');
1226
+        if (!$fp) {
1227
+            throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1228
+                'Make sure it is possible for the webserver to write to ' . $testFile);
1229
+        }
1230
+        fwrite($fp, $testContent);
1231
+        fclose($fp);
1232
+
1233
+        return $testContent;
1234
+    }
1235
+
1236
+    /**
1237
+     * Check if the .htaccess file is working
1238
+     * @param \OCP\IConfig $config
1239
+     * @return bool
1240
+     * @throws Exception
1241
+     * @throws \OC\HintException If the test file can't get written.
1242
+     */
1243
+    public function isHtaccessWorking(\OCP\IConfig $config) {
1244
+
1245
+        if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
1246
+            return true;
1247
+        }
1248
+
1249
+        $testContent = $this->createHtaccessTestFile($config);
1250
+        if ($testContent === false) {
1251
+            return false;
1252
+        }
1253
+
1254
+        $fileName = '/htaccesstest.txt';
1255
+        $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1256
+
1257
+        // accessing the file via http
1258
+        $url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1259
+        try {
1260
+            $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1261
+        } catch (\Exception $e) {
1262
+            $content = false;
1263
+        }
1264
+
1265
+        // cleanup
1266
+        @unlink($testFile);
1267
+
1268
+        /*
1269 1269
 		 * If the content is not equal to test content our .htaccess
1270 1270
 		 * is working as required
1271 1271
 		 */
1272
-		return $content !== $testContent;
1273
-	}
1274
-
1275
-	/**
1276
-	 * Check if the setlocal call does not work. This can happen if the right
1277
-	 * local packages are not available on the server.
1278
-	 *
1279
-	 * @return bool
1280
-	 */
1281
-	public static function isSetLocaleWorking() {
1282
-		\Patchwork\Utf8\Bootup::initLocale();
1283
-		if ('' === basename('§')) {
1284
-			return false;
1285
-		}
1286
-		return true;
1287
-	}
1288
-
1289
-	/**
1290
-	 * Check if it's possible to get the inline annotations
1291
-	 *
1292
-	 * @return bool
1293
-	 */
1294
-	public static function isAnnotationsWorking() {
1295
-		$reflection = new \ReflectionMethod(__METHOD__);
1296
-		$docs = $reflection->getDocComment();
1297
-
1298
-		return (is_string($docs) && strlen($docs) > 50);
1299
-	}
1300
-
1301
-	/**
1302
-	 * Check if the PHP module fileinfo is loaded.
1303
-	 *
1304
-	 * @return bool
1305
-	 */
1306
-	public static function fileInfoLoaded() {
1307
-		return function_exists('finfo_open');
1308
-	}
1309
-
1310
-	/**
1311
-	 * clear all levels of output buffering
1312
-	 *
1313
-	 * @return void
1314
-	 */
1315
-	public static function obEnd() {
1316
-		while (ob_get_level()) {
1317
-			ob_end_clean();
1318
-		}
1319
-	}
1320
-
1321
-	/**
1322
-	 * Checks whether the server is running on Mac OS X
1323
-	 *
1324
-	 * @return bool true if running on Mac OS X, false otherwise
1325
-	 */
1326
-	public static function runningOnMac() {
1327
-		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1328
-	}
1329
-
1330
-	/**
1331
-	 * Checks whether server is running on HHVM
1332
-	 *
1333
-	 * @return bool True if running on HHVM, false otherwise
1334
-	 */
1335
-	public static function runningOnHhvm() {
1336
-		return defined('HHVM_VERSION');
1337
-	}
1338
-
1339
-	/**
1340
-	 * Handles the case that there may not be a theme, then check if a "default"
1341
-	 * theme exists and take that one
1342
-	 *
1343
-	 * @return string the theme
1344
-	 */
1345
-	public static function getTheme() {
1346
-		$theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1347
-
1348
-		if ($theme === '') {
1349
-			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1350
-				$theme = 'default';
1351
-			}
1352
-		}
1353
-
1354
-		return $theme;
1355
-	}
1356
-
1357
-	/**
1358
-	 * Clear a single file from the opcode cache
1359
-	 * This is useful for writing to the config file
1360
-	 * in case the opcode cache does not re-validate files
1361
-	 * Returns true if successful, false if unsuccessful:
1362
-	 * caller should fall back on clearing the entire cache
1363
-	 * with clearOpcodeCache() if unsuccessful
1364
-	 *
1365
-	 * @param string $path the path of the file to clear from the cache
1366
-	 * @return bool true if underlying function returns true, otherwise false
1367
-	 */
1368
-	public static function deleteFromOpcodeCache($path) {
1369
-		$ret = false;
1370
-		if ($path) {
1371
-			// APC >= 3.1.1
1372
-			if (function_exists('apc_delete_file')) {
1373
-				$ret = @apc_delete_file($path);
1374
-			}
1375
-			// Zend OpCache >= 7.0.0, PHP >= 5.5.0
1376
-			if (function_exists('opcache_invalidate')) {
1377
-				$ret = opcache_invalidate($path);
1378
-			}
1379
-		}
1380
-		return $ret;
1381
-	}
1382
-
1383
-	/**
1384
-	 * Clear the opcode cache if one exists
1385
-	 * This is necessary for writing to the config file
1386
-	 * in case the opcode cache does not re-validate files
1387
-	 *
1388
-	 * @return void
1389
-	 * @suppress PhanDeprecatedFunction
1390
-	 * @suppress PhanUndeclaredConstant
1391
-	 */
1392
-	public static function clearOpcodeCache() {
1393
-		// APC
1394
-		if (function_exists('apc_clear_cache')) {
1395
-			apc_clear_cache();
1396
-		}
1397
-		// Zend Opcache
1398
-		if (function_exists('accelerator_reset')) {
1399
-			accelerator_reset();
1400
-		}
1401
-		// XCache
1402
-		if (function_exists('xcache_clear_cache')) {
1403
-			if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
1404
-				\OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN);
1405
-			} else {
1406
-				@xcache_clear_cache(XC_TYPE_PHP, 0);
1407
-			}
1408
-		}
1409
-		// Opcache (PHP >= 5.5)
1410
-		if (function_exists('opcache_reset')) {
1411
-			opcache_reset();
1412
-		}
1413
-	}
1414
-
1415
-	/**
1416
-	 * Normalize a unicode string
1417
-	 *
1418
-	 * @param string $value a not normalized string
1419
-	 * @return bool|string
1420
-	 */
1421
-	public static function normalizeUnicode($value) {
1422
-		if(Normalizer::isNormalized($value)) {
1423
-			return $value;
1424
-		}
1425
-
1426
-		$normalizedValue = Normalizer::normalize($value);
1427
-		if ($normalizedValue === null || $normalizedValue === false) {
1428
-			\OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1429
-			return $value;
1430
-		}
1431
-
1432
-		return $normalizedValue;
1433
-	}
1434
-
1435
-	/**
1436
-	 * A human readable string is generated based on version and build number
1437
-	 *
1438
-	 * @return string
1439
-	 */
1440
-	public static function getHumanVersion() {
1441
-		$version = OC_Util::getVersionString();
1442
-		$build = OC_Util::getBuild();
1443
-		if (!empty($build) and OC_Util::getChannel() === 'daily') {
1444
-			$version .= ' Build:' . $build;
1445
-		}
1446
-		return $version;
1447
-	}
1448
-
1449
-	/**
1450
-	 * Returns whether the given file name is valid
1451
-	 *
1452
-	 * @param string $file file name to check
1453
-	 * @return bool true if the file name is valid, false otherwise
1454
-	 * @deprecated use \OC\Files\View::verifyPath()
1455
-	 */
1456
-	public static function isValidFileName($file) {
1457
-		$trimmed = trim($file);
1458
-		if ($trimmed === '') {
1459
-			return false;
1460
-		}
1461
-		if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1462
-			return false;
1463
-		}
1464
-
1465
-		// detect part files
1466
-		if (preg_match('/' . \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX . '/', $trimmed) !== 0) {
1467
-			return false;
1468
-		}
1469
-
1470
-		foreach (str_split($trimmed) as $char) {
1471
-			if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1472
-				return false;
1473
-			}
1474
-		}
1475
-		return true;
1476
-	}
1477
-
1478
-	/**
1479
-	 * Check whether the instance needs to perform an upgrade,
1480
-	 * either when the core version is higher or any app requires
1481
-	 * an upgrade.
1482
-	 *
1483
-	 * @param \OC\SystemConfig $config
1484
-	 * @return bool whether the core or any app needs an upgrade
1485
-	 * @throws \OC\HintException When the upgrade from the given version is not allowed
1486
-	 */
1487
-	public static function needUpgrade(\OC\SystemConfig $config) {
1488
-		if ($config->getValue('installed', false)) {
1489
-			$installedVersion = $config->getValue('version', '0.0.0');
1490
-			$currentVersion = implode('.', \OCP\Util::getVersion());
1491
-			$versionDiff = version_compare($currentVersion, $installedVersion);
1492
-			if ($versionDiff > 0) {
1493
-				return true;
1494
-			} else if ($config->getValue('debug', false) && $versionDiff < 0) {
1495
-				// downgrade with debug
1496
-				$installedMajor = explode('.', $installedVersion);
1497
-				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1498
-				$currentMajor = explode('.', $currentVersion);
1499
-				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1500
-				if ($installedMajor === $currentMajor) {
1501
-					// Same major, allow downgrade for developers
1502
-					return true;
1503
-				} else {
1504
-					// downgrade attempt, throw exception
1505
-					throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1506
-				}
1507
-			} else if ($versionDiff < 0) {
1508
-				// downgrade attempt, throw exception
1509
-				throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1510
-			}
1511
-
1512
-			// also check for upgrades for apps (independently from the user)
1513
-			$apps = \OC_App::getEnabledApps(false, true);
1514
-			$shouldUpgrade = false;
1515
-			foreach ($apps as $app) {
1516
-				if (\OC_App::shouldUpgrade($app)) {
1517
-					$shouldUpgrade = true;
1518
-					break;
1519
-				}
1520
-			}
1521
-			return $shouldUpgrade;
1522
-		} else {
1523
-			return false;
1524
-		}
1525
-	}
1272
+        return $content !== $testContent;
1273
+    }
1274
+
1275
+    /**
1276
+     * Check if the setlocal call does not work. This can happen if the right
1277
+     * local packages are not available on the server.
1278
+     *
1279
+     * @return bool
1280
+     */
1281
+    public static function isSetLocaleWorking() {
1282
+        \Patchwork\Utf8\Bootup::initLocale();
1283
+        if ('' === basename('§')) {
1284
+            return false;
1285
+        }
1286
+        return true;
1287
+    }
1288
+
1289
+    /**
1290
+     * Check if it's possible to get the inline annotations
1291
+     *
1292
+     * @return bool
1293
+     */
1294
+    public static function isAnnotationsWorking() {
1295
+        $reflection = new \ReflectionMethod(__METHOD__);
1296
+        $docs = $reflection->getDocComment();
1297
+
1298
+        return (is_string($docs) && strlen($docs) > 50);
1299
+    }
1300
+
1301
+    /**
1302
+     * Check if the PHP module fileinfo is loaded.
1303
+     *
1304
+     * @return bool
1305
+     */
1306
+    public static function fileInfoLoaded() {
1307
+        return function_exists('finfo_open');
1308
+    }
1309
+
1310
+    /**
1311
+     * clear all levels of output buffering
1312
+     *
1313
+     * @return void
1314
+     */
1315
+    public static function obEnd() {
1316
+        while (ob_get_level()) {
1317
+            ob_end_clean();
1318
+        }
1319
+    }
1320
+
1321
+    /**
1322
+     * Checks whether the server is running on Mac OS X
1323
+     *
1324
+     * @return bool true if running on Mac OS X, false otherwise
1325
+     */
1326
+    public static function runningOnMac() {
1327
+        return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1328
+    }
1329
+
1330
+    /**
1331
+     * Checks whether server is running on HHVM
1332
+     *
1333
+     * @return bool True if running on HHVM, false otherwise
1334
+     */
1335
+    public static function runningOnHhvm() {
1336
+        return defined('HHVM_VERSION');
1337
+    }
1338
+
1339
+    /**
1340
+     * Handles the case that there may not be a theme, then check if a "default"
1341
+     * theme exists and take that one
1342
+     *
1343
+     * @return string the theme
1344
+     */
1345
+    public static function getTheme() {
1346
+        $theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1347
+
1348
+        if ($theme === '') {
1349
+            if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1350
+                $theme = 'default';
1351
+            }
1352
+        }
1353
+
1354
+        return $theme;
1355
+    }
1356
+
1357
+    /**
1358
+     * Clear a single file from the opcode cache
1359
+     * This is useful for writing to the config file
1360
+     * in case the opcode cache does not re-validate files
1361
+     * Returns true if successful, false if unsuccessful:
1362
+     * caller should fall back on clearing the entire cache
1363
+     * with clearOpcodeCache() if unsuccessful
1364
+     *
1365
+     * @param string $path the path of the file to clear from the cache
1366
+     * @return bool true if underlying function returns true, otherwise false
1367
+     */
1368
+    public static function deleteFromOpcodeCache($path) {
1369
+        $ret = false;
1370
+        if ($path) {
1371
+            // APC >= 3.1.1
1372
+            if (function_exists('apc_delete_file')) {
1373
+                $ret = @apc_delete_file($path);
1374
+            }
1375
+            // Zend OpCache >= 7.0.0, PHP >= 5.5.0
1376
+            if (function_exists('opcache_invalidate')) {
1377
+                $ret = opcache_invalidate($path);
1378
+            }
1379
+        }
1380
+        return $ret;
1381
+    }
1382
+
1383
+    /**
1384
+     * Clear the opcode cache if one exists
1385
+     * This is necessary for writing to the config file
1386
+     * in case the opcode cache does not re-validate files
1387
+     *
1388
+     * @return void
1389
+     * @suppress PhanDeprecatedFunction
1390
+     * @suppress PhanUndeclaredConstant
1391
+     */
1392
+    public static function clearOpcodeCache() {
1393
+        // APC
1394
+        if (function_exists('apc_clear_cache')) {
1395
+            apc_clear_cache();
1396
+        }
1397
+        // Zend Opcache
1398
+        if (function_exists('accelerator_reset')) {
1399
+            accelerator_reset();
1400
+        }
1401
+        // XCache
1402
+        if (function_exists('xcache_clear_cache')) {
1403
+            if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
1404
+                \OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN);
1405
+            } else {
1406
+                @xcache_clear_cache(XC_TYPE_PHP, 0);
1407
+            }
1408
+        }
1409
+        // Opcache (PHP >= 5.5)
1410
+        if (function_exists('opcache_reset')) {
1411
+            opcache_reset();
1412
+        }
1413
+    }
1414
+
1415
+    /**
1416
+     * Normalize a unicode string
1417
+     *
1418
+     * @param string $value a not normalized string
1419
+     * @return bool|string
1420
+     */
1421
+    public static function normalizeUnicode($value) {
1422
+        if(Normalizer::isNormalized($value)) {
1423
+            return $value;
1424
+        }
1425
+
1426
+        $normalizedValue = Normalizer::normalize($value);
1427
+        if ($normalizedValue === null || $normalizedValue === false) {
1428
+            \OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1429
+            return $value;
1430
+        }
1431
+
1432
+        return $normalizedValue;
1433
+    }
1434
+
1435
+    /**
1436
+     * A human readable string is generated based on version and build number
1437
+     *
1438
+     * @return string
1439
+     */
1440
+    public static function getHumanVersion() {
1441
+        $version = OC_Util::getVersionString();
1442
+        $build = OC_Util::getBuild();
1443
+        if (!empty($build) and OC_Util::getChannel() === 'daily') {
1444
+            $version .= ' Build:' . $build;
1445
+        }
1446
+        return $version;
1447
+    }
1448
+
1449
+    /**
1450
+     * Returns whether the given file name is valid
1451
+     *
1452
+     * @param string $file file name to check
1453
+     * @return bool true if the file name is valid, false otherwise
1454
+     * @deprecated use \OC\Files\View::verifyPath()
1455
+     */
1456
+    public static function isValidFileName($file) {
1457
+        $trimmed = trim($file);
1458
+        if ($trimmed === '') {
1459
+            return false;
1460
+        }
1461
+        if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1462
+            return false;
1463
+        }
1464
+
1465
+        // detect part files
1466
+        if (preg_match('/' . \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX . '/', $trimmed) !== 0) {
1467
+            return false;
1468
+        }
1469
+
1470
+        foreach (str_split($trimmed) as $char) {
1471
+            if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1472
+                return false;
1473
+            }
1474
+        }
1475
+        return true;
1476
+    }
1477
+
1478
+    /**
1479
+     * Check whether the instance needs to perform an upgrade,
1480
+     * either when the core version is higher or any app requires
1481
+     * an upgrade.
1482
+     *
1483
+     * @param \OC\SystemConfig $config
1484
+     * @return bool whether the core or any app needs an upgrade
1485
+     * @throws \OC\HintException When the upgrade from the given version is not allowed
1486
+     */
1487
+    public static function needUpgrade(\OC\SystemConfig $config) {
1488
+        if ($config->getValue('installed', false)) {
1489
+            $installedVersion = $config->getValue('version', '0.0.0');
1490
+            $currentVersion = implode('.', \OCP\Util::getVersion());
1491
+            $versionDiff = version_compare($currentVersion, $installedVersion);
1492
+            if ($versionDiff > 0) {
1493
+                return true;
1494
+            } else if ($config->getValue('debug', false) && $versionDiff < 0) {
1495
+                // downgrade with debug
1496
+                $installedMajor = explode('.', $installedVersion);
1497
+                $installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1498
+                $currentMajor = explode('.', $currentVersion);
1499
+                $currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1500
+                if ($installedMajor === $currentMajor) {
1501
+                    // Same major, allow downgrade for developers
1502
+                    return true;
1503
+                } else {
1504
+                    // downgrade attempt, throw exception
1505
+                    throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1506
+                }
1507
+            } else if ($versionDiff < 0) {
1508
+                // downgrade attempt, throw exception
1509
+                throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1510
+            }
1511
+
1512
+            // also check for upgrades for apps (independently from the user)
1513
+            $apps = \OC_App::getEnabledApps(false, true);
1514
+            $shouldUpgrade = false;
1515
+            foreach ($apps as $app) {
1516
+                if (\OC_App::shouldUpgrade($app)) {
1517
+                    $shouldUpgrade = true;
1518
+                    break;
1519
+                }
1520
+            }
1521
+            return $shouldUpgrade;
1522
+        } else {
1523
+            return false;
1524
+        }
1525
+    }
1526 1526
 
1527 1527
 }
Please login to merge, or discard this patch.
lib/private/Share/Share.php 1 patch
Indentation   +2073 added lines, -2073 removed lines patch added patch discarded remove patch
@@ -57,2087 +57,2087 @@
 block discarded – undo
57 57
  */
58 58
 class Share extends Constants {
59 59
 
60
-	/** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
61
-	 * Construct permissions for share() and setPermissions with Or (|) e.g.
62
-	 * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
63
-	 *
64
-	 * Check if permission is granted with And (&) e.g. Check if delete is
65
-	 * granted: if ($permissions & PERMISSION_DELETE)
66
-	 *
67
-	 * Remove permissions with And (&) and Not (~) e.g. Remove the update
68
-	 * permission: $permissions &= ~PERMISSION_UPDATE
69
-	 *
70
-	 * Apps are required to handle permissions on their own, this class only
71
-	 * stores and manages the permissions of shares
72
-	 * @see lib/public/constants.php
73
-	 */
74
-
75
-	/**
76
-	 * Register a sharing backend class that implements OCP\Share_Backend for an item type
77
-	 * @param string $itemType Item type
78
-	 * @param string $class Backend class
79
-	 * @param string $collectionOf (optional) Depends on item type
80
-	 * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
81
-	 * @return boolean true if backend is registered or false if error
82
-	 */
83
-	public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
84
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') == 'yes') {
85
-			if (!isset(self::$backendTypes[$itemType])) {
86
-				self::$backendTypes[$itemType] = array(
87
-					'class' => $class,
88
-					'collectionOf' => $collectionOf,
89
-					'supportedFileExtensions' => $supportedFileExtensions
90
-				);
91
-				if(count(self::$backendTypes) === 1) {
92
-					Util::addScript('core', 'merged-share-backend');
93
-					\OC_Util::addStyle('core', 'share');
94
-				}
95
-				return true;
96
-			}
97
-			\OCP\Util::writeLog('OCP\Share',
98
-				'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
99
-				.' is already registered for '.$itemType,
100
-				\OCP\Util::WARN);
101
-		}
102
-		return false;
103
-	}
104
-
105
-	/**
106
-	 * Get the items of item type shared with the current user
107
-	 * @param string $itemType
108
-	 * @param int $format (optional) Format type must be defined by the backend
109
-	 * @param mixed $parameters (optional)
110
-	 * @param int $limit Number of items to return (optional) Returns all by default
111
-	 * @param boolean $includeCollections (optional)
112
-	 * @return mixed Return depends on format
113
-	 */
114
-	public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
115
-											  $parameters = null, $limit = -1, $includeCollections = false) {
116
-		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
117
-			$parameters, $limit, $includeCollections);
118
-	}
119
-
120
-	/**
121
-	 * Get the items of item type shared with a user
122
-	 * @param string $itemType
123
-	 * @param string $user id for which user we want the shares
124
-	 * @param int $format (optional) Format type must be defined by the backend
125
-	 * @param mixed $parameters (optional)
126
-	 * @param int $limit Number of items to return (optional) Returns all by default
127
-	 * @param boolean $includeCollections (optional)
128
-	 * @return mixed Return depends on format
129
-	 */
130
-	public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
131
-												  $parameters = null, $limit = -1, $includeCollections = false) {
132
-		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
133
-			$parameters, $limit, $includeCollections);
134
-	}
135
-
136
-	/**
137
-	 * Get the item of item type shared with a given user by source
138
-	 * @param string $itemType
139
-	 * @param string $itemSource
140
-	 * @param string $user User to whom the item was shared
141
-	 * @param string $owner Owner of the share
142
-	 * @param int $shareType only look for a specific share type
143
-	 * @return array Return list of items with file_target, permissions and expiration
144
-	 */
145
-	public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
146
-		$shares = array();
147
-		$fileDependent = false;
148
-
149
-		$where = 'WHERE';
150
-		$fileDependentWhere = '';
151
-		if ($itemType === 'file' || $itemType === 'folder') {
152
-			$fileDependent = true;
153
-			$column = 'file_source';
154
-			$fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
155
-			$fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
156
-		} else {
157
-			$column = 'item_source';
158
-		}
159
-
160
-		$select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
161
-
162
-		$where .= ' `' . $column . '` = ? AND `item_type` = ? ';
163
-		$arguments = array($itemSource, $itemType);
164
-		// for link shares $user === null
165
-		if ($user !== null) {
166
-			$where .= ' AND `share_with` = ? ';
167
-			$arguments[] = $user;
168
-		}
169
-
170
-		if ($shareType !== null) {
171
-			$where .= ' AND `share_type` = ? ';
172
-			$arguments[] = $shareType;
173
-		}
174
-
175
-		if ($owner !== null) {
176
-			$where .= ' AND `uid_owner` = ? ';
177
-			$arguments[] = $owner;
178
-		}
179
-
180
-		$query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
181
-
182
-		$result = \OC_DB::executeAudited($query, $arguments);
183
-
184
-		while ($row = $result->fetchRow()) {
185
-			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
186
-				continue;
187
-			}
188
-			if ($fileDependent && (int)$row['file_parent'] === -1) {
189
-				// if it is a mount point we need to get the path from the mount manager
190
-				$mountManager = \OC\Files\Filesystem::getMountManager();
191
-				$mountPoint = $mountManager->findByStorageId($row['storage_id']);
192
-				if (!empty($mountPoint)) {
193
-					$path = $mountPoint[0]->getMountPoint();
194
-					$path = trim($path, '/');
195
-					$path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
196
-					$row['path'] = $path;
197
-				} else {
198
-					\OC::$server->getLogger()->warning(
199
-						'Could not resolve mount point for ' . $row['storage_id'],
200
-						['app' => 'OCP\Share']
201
-					);
202
-				}
203
-			}
204
-			$shares[] = $row;
205
-		}
206
-
207
-		//if didn't found a result than let's look for a group share.
208
-		if(empty($shares) && $user !== null) {
209
-			$userObject = \OC::$server->getUserManager()->get($user);
210
-			$groups = [];
211
-			if ($userObject) {
212
-				$groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
213
-			}
214
-
215
-			if (!empty($groups)) {
216
-				$where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
217
-				$arguments = array($itemSource, $itemType, $groups);
218
-				$types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
219
-
220
-				if ($owner !== null) {
221
-					$where .= ' AND `uid_owner` = ?';
222
-					$arguments[] = $owner;
223
-					$types[] = null;
224
-				}
225
-
226
-				// TODO: inject connection, hopefully one day in the future when this
227
-				// class isn't static anymore...
228
-				$conn = \OC::$server->getDatabaseConnection();
229
-				$result = $conn->executeQuery(
230
-					'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
231
-					$arguments,
232
-					$types
233
-				);
234
-
235
-				while ($row = $result->fetch()) {
236
-					$shares[] = $row;
237
-				}
238
-			}
239
-		}
240
-
241
-		return $shares;
242
-
243
-	}
244
-
245
-	/**
246
-	 * Get the item of item type shared with the current user by source
247
-	 * @param string $itemType
248
-	 * @param string $itemSource
249
-	 * @param int $format (optional) Format type must be defined by the backend
250
-	 * @param mixed $parameters
251
-	 * @param boolean $includeCollections
252
-	 * @param string $shareWith (optional) define against which user should be checked, default: current user
253
-	 * @return array
254
-	 */
255
-	public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
256
-													 $parameters = null, $includeCollections = false, $shareWith = null) {
257
-		$shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
258
-		return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
259
-			$parameters, 1, $includeCollections, true);
260
-	}
261
-
262
-	/**
263
-	 * Based on the given token the share information will be returned - password protected shares will be verified
264
-	 * @param string $token
265
-	 * @param bool $checkPasswordProtection
266
-	 * @return array|boolean false will be returned in case the token is unknown or unauthorized
267
-	 */
268
-	public static function getShareByToken($token, $checkPasswordProtection = true) {
269
-		$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
270
-		$result = $query->execute(array($token));
271
-		if ($result === false) {
272
-			\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
273
-		}
274
-		$row = $result->fetchRow();
275
-		if ($row === false) {
276
-			return false;
277
-		}
278
-		if (is_array($row) and self::expireItem($row)) {
279
-			return false;
280
-		}
281
-
282
-		// password protected shares need to be authenticated
283
-		if ($checkPasswordProtection && !\OC\Share\Share::checkPasswordProtectedShare($row)) {
284
-			return false;
285
-		}
286
-
287
-		return $row;
288
-	}
289
-
290
-	/**
291
-	 * resolves reshares down to the last real share
292
-	 * @param array $linkItem
293
-	 * @return array file owner
294
-	 */
295
-	public static function resolveReShare($linkItem)
296
-	{
297
-		if (isset($linkItem['parent'])) {
298
-			$parent = $linkItem['parent'];
299
-			while (isset($parent)) {
300
-				$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1);
301
-				$item = $query->execute(array($parent))->fetchRow();
302
-				if (isset($item['parent'])) {
303
-					$parent = $item['parent'];
304
-				} else {
305
-					return $item;
306
-				}
307
-			}
308
-		}
309
-		return $linkItem;
310
-	}
311
-
312
-
313
-	/**
314
-	 * Get the shared items of item type owned by the current user
315
-	 * @param string $itemType
316
-	 * @param int $format (optional) Format type must be defined by the backend
317
-	 * @param mixed $parameters
318
-	 * @param int $limit Number of items to return (optional) Returns all by default
319
-	 * @param boolean $includeCollections
320
-	 * @return mixed Return depends on format
321
-	 */
322
-	public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
323
-										  $limit = -1, $includeCollections = false) {
324
-		return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
325
-			$parameters, $limit, $includeCollections);
326
-	}
327
-
328
-	/**
329
-	 * Get the shared item of item type owned by the current user
330
-	 * @param string $itemType
331
-	 * @param string $itemSource
332
-	 * @param int $format (optional) Format type must be defined by the backend
333
-	 * @param mixed $parameters
334
-	 * @param boolean $includeCollections
335
-	 * @return mixed Return depends on format
336
-	 */
337
-	public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
338
-										 $parameters = null, $includeCollections = false) {
339
-		return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
340
-			$parameters, -1, $includeCollections);
341
-	}
342
-
343
-	/**
344
-	 * Share an item with a user, group, or via private link
345
-	 * @param string $itemType
346
-	 * @param string $itemSource
347
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
348
-	 * @param string $shareWith User or group the item is being shared with
349
-	 * @param int $permissions CRUDS
350
-	 * @param string $itemSourceName
351
-	 * @param \DateTime|null $expirationDate
352
-	 * @param bool|null $passwordChanged
353
-	 * @return boolean|string Returns true on success or false on failure, Returns token on success for links
354
-	 * @throws \OC\HintException when the share type is remote and the shareWith is invalid
355
-	 * @throws \Exception
356
-	 * @since 5.0.0 - parameter $itemSourceName was added in 6.0.0, parameter $expirationDate was added in 7.0.0, parameter $passwordChanged added in 9.0.0
357
-	 */
358
-	public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
359
-
360
-		$backend = self::getBackend($itemType);
361
-		$l = \OC::$server->getL10N('lib');
362
-
363
-		if ($backend->isShareTypeAllowed($shareType) === false) {
364
-			$message = 'Sharing %s failed, because the backend does not allow shares from type %i';
365
-			$message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
366
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), \OCP\Util::DEBUG);
367
-			throw new \Exception($message_t);
368
-		}
369
-
370
-		$uidOwner = \OC_User::getUser();
371
-		$shareWithinGroupOnly = self::shareWithGroupMembersOnly();
372
-
373
-		if (is_null($itemSourceName)) {
374
-			$itemSourceName = $itemSource;
375
-		}
376
-		$itemName = $itemSourceName;
377
-
378
-		// check if file can be shared
379
-		if ($itemType === 'file' or $itemType === 'folder') {
380
-			$path = \OC\Files\Filesystem::getPath($itemSource);
381
-			$itemName = $path;
382
-
383
-			// verify that the file exists before we try to share it
384
-			if (!$path) {
385
-				$message = 'Sharing %s failed, because the file does not exist';
386
-				$message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
387
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
388
-				throw new \Exception($message_t);
389
-			}
390
-			// verify that the user has share permission
391
-			if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
392
-				$message = 'You are not allowed to share %s';
393
-				$message_t = $l->t('You are not allowed to share %s', [$path]);
394
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $path), \OCP\Util::DEBUG);
395
-				throw new \Exception($message_t);
396
-			}
397
-		}
398
-
399
-		//verify that we don't share a folder which already contains a share mount point
400
-		if ($itemType === 'folder') {
401
-			$path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
402
-			$mountManager = \OC\Files\Filesystem::getMountManager();
403
-			$mounts = $mountManager->findIn($path);
404
-			foreach ($mounts as $mount) {
405
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
406
-					$message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
407
-					\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
408
-					throw new \Exception($message);
409
-				}
410
-
411
-			}
412
-		}
413
-
414
-		// single file shares should never have delete permissions
415
-		if ($itemType === 'file') {
416
-			$permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
417
-		}
418
-
419
-		//Validate expirationDate
420
-		if ($expirationDate !== null) {
421
-			try {
422
-				/*
60
+    /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
61
+     * Construct permissions for share() and setPermissions with Or (|) e.g.
62
+     * Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
63
+     *
64
+     * Check if permission is granted with And (&) e.g. Check if delete is
65
+     * granted: if ($permissions & PERMISSION_DELETE)
66
+     *
67
+     * Remove permissions with And (&) and Not (~) e.g. Remove the update
68
+     * permission: $permissions &= ~PERMISSION_UPDATE
69
+     *
70
+     * Apps are required to handle permissions on their own, this class only
71
+     * stores and manages the permissions of shares
72
+     * @see lib/public/constants.php
73
+     */
74
+
75
+    /**
76
+     * Register a sharing backend class that implements OCP\Share_Backend for an item type
77
+     * @param string $itemType Item type
78
+     * @param string $class Backend class
79
+     * @param string $collectionOf (optional) Depends on item type
80
+     * @param array $supportedFileExtensions (optional) List of supported file extensions if this item type depends on files
81
+     * @return boolean true if backend is registered or false if error
82
+     */
83
+    public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
84
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') == 'yes') {
85
+            if (!isset(self::$backendTypes[$itemType])) {
86
+                self::$backendTypes[$itemType] = array(
87
+                    'class' => $class,
88
+                    'collectionOf' => $collectionOf,
89
+                    'supportedFileExtensions' => $supportedFileExtensions
90
+                );
91
+                if(count(self::$backendTypes) === 1) {
92
+                    Util::addScript('core', 'merged-share-backend');
93
+                    \OC_Util::addStyle('core', 'share');
94
+                }
95
+                return true;
96
+            }
97
+            \OCP\Util::writeLog('OCP\Share',
98
+                'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class']
99
+                .' is already registered for '.$itemType,
100
+                \OCP\Util::WARN);
101
+        }
102
+        return false;
103
+    }
104
+
105
+    /**
106
+     * Get the items of item type shared with the current user
107
+     * @param string $itemType
108
+     * @param int $format (optional) Format type must be defined by the backend
109
+     * @param mixed $parameters (optional)
110
+     * @param int $limit Number of items to return (optional) Returns all by default
111
+     * @param boolean $includeCollections (optional)
112
+     * @return mixed Return depends on format
113
+     */
114
+    public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
115
+                                                $parameters = null, $limit = -1, $includeCollections = false) {
116
+        return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
117
+            $parameters, $limit, $includeCollections);
118
+    }
119
+
120
+    /**
121
+     * Get the items of item type shared with a user
122
+     * @param string $itemType
123
+     * @param string $user id for which user we want the shares
124
+     * @param int $format (optional) Format type must be defined by the backend
125
+     * @param mixed $parameters (optional)
126
+     * @param int $limit Number of items to return (optional) Returns all by default
127
+     * @param boolean $includeCollections (optional)
128
+     * @return mixed Return depends on format
129
+     */
130
+    public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
131
+                                                    $parameters = null, $limit = -1, $includeCollections = false) {
132
+        return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
133
+            $parameters, $limit, $includeCollections);
134
+    }
135
+
136
+    /**
137
+     * Get the item of item type shared with a given user by source
138
+     * @param string $itemType
139
+     * @param string $itemSource
140
+     * @param string $user User to whom the item was shared
141
+     * @param string $owner Owner of the share
142
+     * @param int $shareType only look for a specific share type
143
+     * @return array Return list of items with file_target, permissions and expiration
144
+     */
145
+    public static function getItemSharedWithUser($itemType, $itemSource, $user, $owner = null, $shareType = null) {
146
+        $shares = array();
147
+        $fileDependent = false;
148
+
149
+        $where = 'WHERE';
150
+        $fileDependentWhere = '';
151
+        if ($itemType === 'file' || $itemType === 'folder') {
152
+            $fileDependent = true;
153
+            $column = 'file_source';
154
+            $fileDependentWhere = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
155
+            $fileDependentWhere .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
156
+        } else {
157
+            $column = 'item_source';
158
+        }
159
+
160
+        $select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent);
161
+
162
+        $where .= ' `' . $column . '` = ? AND `item_type` = ? ';
163
+        $arguments = array($itemSource, $itemType);
164
+        // for link shares $user === null
165
+        if ($user !== null) {
166
+            $where .= ' AND `share_with` = ? ';
167
+            $arguments[] = $user;
168
+        }
169
+
170
+        if ($shareType !== null) {
171
+            $where .= ' AND `share_type` = ? ';
172
+            $arguments[] = $shareType;
173
+        }
174
+
175
+        if ($owner !== null) {
176
+            $where .= ' AND `uid_owner` = ? ';
177
+            $arguments[] = $owner;
178
+        }
179
+
180
+        $query = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` '. $fileDependentWhere . $where);
181
+
182
+        $result = \OC_DB::executeAudited($query, $arguments);
183
+
184
+        while ($row = $result->fetchRow()) {
185
+            if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
186
+                continue;
187
+            }
188
+            if ($fileDependent && (int)$row['file_parent'] === -1) {
189
+                // if it is a mount point we need to get the path from the mount manager
190
+                $mountManager = \OC\Files\Filesystem::getMountManager();
191
+                $mountPoint = $mountManager->findByStorageId($row['storage_id']);
192
+                if (!empty($mountPoint)) {
193
+                    $path = $mountPoint[0]->getMountPoint();
194
+                    $path = trim($path, '/');
195
+                    $path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt`
196
+                    $row['path'] = $path;
197
+                } else {
198
+                    \OC::$server->getLogger()->warning(
199
+                        'Could not resolve mount point for ' . $row['storage_id'],
200
+                        ['app' => 'OCP\Share']
201
+                    );
202
+                }
203
+            }
204
+            $shares[] = $row;
205
+        }
206
+
207
+        //if didn't found a result than let's look for a group share.
208
+        if(empty($shares) && $user !== null) {
209
+            $userObject = \OC::$server->getUserManager()->get($user);
210
+            $groups = [];
211
+            if ($userObject) {
212
+                $groups = \OC::$server->getGroupManager()->getUserGroupIds($userObject);
213
+            }
214
+
215
+            if (!empty($groups)) {
216
+                $where = $fileDependentWhere . ' WHERE `' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)';
217
+                $arguments = array($itemSource, $itemType, $groups);
218
+                $types = array(null, null, IQueryBuilder::PARAM_STR_ARRAY);
219
+
220
+                if ($owner !== null) {
221
+                    $where .= ' AND `uid_owner` = ?';
222
+                    $arguments[] = $owner;
223
+                    $types[] = null;
224
+                }
225
+
226
+                // TODO: inject connection, hopefully one day in the future when this
227
+                // class isn't static anymore...
228
+                $conn = \OC::$server->getDatabaseConnection();
229
+                $result = $conn->executeQuery(
230
+                    'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
231
+                    $arguments,
232
+                    $types
233
+                );
234
+
235
+                while ($row = $result->fetch()) {
236
+                    $shares[] = $row;
237
+                }
238
+            }
239
+        }
240
+
241
+        return $shares;
242
+
243
+    }
244
+
245
+    /**
246
+     * Get the item of item type shared with the current user by source
247
+     * @param string $itemType
248
+     * @param string $itemSource
249
+     * @param int $format (optional) Format type must be defined by the backend
250
+     * @param mixed $parameters
251
+     * @param boolean $includeCollections
252
+     * @param string $shareWith (optional) define against which user should be checked, default: current user
253
+     * @return array
254
+     */
255
+    public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
256
+                                                        $parameters = null, $includeCollections = false, $shareWith = null) {
257
+        $shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
258
+        return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
259
+            $parameters, 1, $includeCollections, true);
260
+    }
261
+
262
+    /**
263
+     * Based on the given token the share information will be returned - password protected shares will be verified
264
+     * @param string $token
265
+     * @param bool $checkPasswordProtection
266
+     * @return array|boolean false will be returned in case the token is unknown or unauthorized
267
+     */
268
+    public static function getShareByToken($token, $checkPasswordProtection = true) {
269
+        $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
270
+        $result = $query->execute(array($token));
271
+        if ($result === false) {
272
+            \OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
273
+        }
274
+        $row = $result->fetchRow();
275
+        if ($row === false) {
276
+            return false;
277
+        }
278
+        if (is_array($row) and self::expireItem($row)) {
279
+            return false;
280
+        }
281
+
282
+        // password protected shares need to be authenticated
283
+        if ($checkPasswordProtection && !\OC\Share\Share::checkPasswordProtectedShare($row)) {
284
+            return false;
285
+        }
286
+
287
+        return $row;
288
+    }
289
+
290
+    /**
291
+     * resolves reshares down to the last real share
292
+     * @param array $linkItem
293
+     * @return array file owner
294
+     */
295
+    public static function resolveReShare($linkItem)
296
+    {
297
+        if (isset($linkItem['parent'])) {
298
+            $parent = $linkItem['parent'];
299
+            while (isset($parent)) {
300
+                $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `id` = ?', 1);
301
+                $item = $query->execute(array($parent))->fetchRow();
302
+                if (isset($item['parent'])) {
303
+                    $parent = $item['parent'];
304
+                } else {
305
+                    return $item;
306
+                }
307
+            }
308
+        }
309
+        return $linkItem;
310
+    }
311
+
312
+
313
+    /**
314
+     * Get the shared items of item type owned by the current user
315
+     * @param string $itemType
316
+     * @param int $format (optional) Format type must be defined by the backend
317
+     * @param mixed $parameters
318
+     * @param int $limit Number of items to return (optional) Returns all by default
319
+     * @param boolean $includeCollections
320
+     * @return mixed Return depends on format
321
+     */
322
+    public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
323
+                                            $limit = -1, $includeCollections = false) {
324
+        return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
325
+            $parameters, $limit, $includeCollections);
326
+    }
327
+
328
+    /**
329
+     * Get the shared item of item type owned by the current user
330
+     * @param string $itemType
331
+     * @param string $itemSource
332
+     * @param int $format (optional) Format type must be defined by the backend
333
+     * @param mixed $parameters
334
+     * @param boolean $includeCollections
335
+     * @return mixed Return depends on format
336
+     */
337
+    public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
338
+                                            $parameters = null, $includeCollections = false) {
339
+        return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
340
+            $parameters, -1, $includeCollections);
341
+    }
342
+
343
+    /**
344
+     * Share an item with a user, group, or via private link
345
+     * @param string $itemType
346
+     * @param string $itemSource
347
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
348
+     * @param string $shareWith User or group the item is being shared with
349
+     * @param int $permissions CRUDS
350
+     * @param string $itemSourceName
351
+     * @param \DateTime|null $expirationDate
352
+     * @param bool|null $passwordChanged
353
+     * @return boolean|string Returns true on success or false on failure, Returns token on success for links
354
+     * @throws \OC\HintException when the share type is remote and the shareWith is invalid
355
+     * @throws \Exception
356
+     * @since 5.0.0 - parameter $itemSourceName was added in 6.0.0, parameter $expirationDate was added in 7.0.0, parameter $passwordChanged added in 9.0.0
357
+     */
358
+    public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null, $passwordChanged = null) {
359
+
360
+        $backend = self::getBackend($itemType);
361
+        $l = \OC::$server->getL10N('lib');
362
+
363
+        if ($backend->isShareTypeAllowed($shareType) === false) {
364
+            $message = 'Sharing %s failed, because the backend does not allow shares from type %i';
365
+            $message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
366
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareType), \OCP\Util::DEBUG);
367
+            throw new \Exception($message_t);
368
+        }
369
+
370
+        $uidOwner = \OC_User::getUser();
371
+        $shareWithinGroupOnly = self::shareWithGroupMembersOnly();
372
+
373
+        if (is_null($itemSourceName)) {
374
+            $itemSourceName = $itemSource;
375
+        }
376
+        $itemName = $itemSourceName;
377
+
378
+        // check if file can be shared
379
+        if ($itemType === 'file' or $itemType === 'folder') {
380
+            $path = \OC\Files\Filesystem::getPath($itemSource);
381
+            $itemName = $path;
382
+
383
+            // verify that the file exists before we try to share it
384
+            if (!$path) {
385
+                $message = 'Sharing %s failed, because the file does not exist';
386
+                $message_t = $l->t('Sharing %s failed, because the file does not exist', array($itemSourceName));
387
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
388
+                throw new \Exception($message_t);
389
+            }
390
+            // verify that the user has share permission
391
+            if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
392
+                $message = 'You are not allowed to share %s';
393
+                $message_t = $l->t('You are not allowed to share %s', [$path]);
394
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $path), \OCP\Util::DEBUG);
395
+                throw new \Exception($message_t);
396
+            }
397
+        }
398
+
399
+        //verify that we don't share a folder which already contains a share mount point
400
+        if ($itemType === 'folder') {
401
+            $path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
402
+            $mountManager = \OC\Files\Filesystem::getMountManager();
403
+            $mounts = $mountManager->findIn($path);
404
+            foreach ($mounts as $mount) {
405
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
406
+                    $message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
407
+                    \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
408
+                    throw new \Exception($message);
409
+                }
410
+
411
+            }
412
+        }
413
+
414
+        // single file shares should never have delete permissions
415
+        if ($itemType === 'file') {
416
+            $permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
417
+        }
418
+
419
+        //Validate expirationDate
420
+        if ($expirationDate !== null) {
421
+            try {
422
+                /*
423 423
 				 * Reuse the validateExpireDate.
424 424
 				 * We have to pass time() since the second arg is the time
425 425
 				 * the file was shared, since it is not shared yet we just use
426 426
 				 * the current time.
427 427
 				 */
428
-				$expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
429
-			} catch (\Exception $e) {
430
-				throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
431
-			}
432
-		}
433
-
434
-		// Verify share type and sharing conditions are met
435
-		if ($shareType === self::SHARE_TYPE_USER) {
436
-			if ($shareWith == $uidOwner) {
437
-				$message = 'Sharing %s failed, because you can not share with yourself';
438
-				$message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
439
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
440
-				throw new \Exception($message_t);
441
-			}
442
-			if (!\OC::$server->getUserManager()->userExists($shareWith)) {
443
-				$message = 'Sharing %s failed, because the user %s does not exist';
444
-				$message_t = $l->t('Sharing %s failed, because the user %s does not exist', array($itemSourceName, $shareWith));
445
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
446
-				throw new \Exception($message_t);
447
-			}
448
-			if ($shareWithinGroupOnly) {
449
-				$userManager = \OC::$server->getUserManager();
450
-				$groupManager = \OC::$server->getGroupManager();
451
-				$userOwner = $userManager->get($uidOwner);
452
-				$userShareWith = $userManager->get($shareWith);
453
-				$groupsOwner = [];
454
-				$groupsShareWith = [];
455
-				if ($userOwner) {
456
-					$groupsOwner = $groupManager->getUserGroupIds($userOwner);
457
-				}
458
-				if ($userShareWith) {
459
-					$groupsShareWith = $groupManager->getUserGroupIds($userShareWith);
460
-				}
461
-				$inGroup = array_intersect($groupsOwner, $groupsShareWith);
462
-				if (empty($inGroup)) {
463
-					$message = 'Sharing %s failed, because the user '
464
-						.'%s is not a member of any groups that %s is a member of';
465
-					$message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemName, $shareWith, $uidOwner));
466
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), \OCP\Util::DEBUG);
467
-					throw new \Exception($message_t);
468
-				}
469
-			}
470
-			// Check if the item source is already shared with the user, either from the same owner or a different user
471
-			if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
472
-				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
473
-				// Only allow the same share to occur again if it is the same
474
-				// owner and is not a user share, this use case is for increasing
475
-				// permissions for a specific user
476
-				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
477
-					$message = 'Sharing %s failed, because this item is already shared with %s';
478
-					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
479
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
480
-					throw new \Exception($message_t);
481
-				}
482
-			}
483
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
484
-				$shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
485
-				// Only allow the same share to occur again if it is the same
486
-				// owner and is not a user share, this use case is for increasing
487
-				// permissions for a specific user
488
-				if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
489
-					$message = 'Sharing %s failed, because this item is already shared with user %s';
490
-					$message_t = $l->t('Sharing %s failed, because this item is already shared with user %s', array($itemSourceName, $shareWith));
491
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::ERROR);
492
-					throw new \Exception($message_t);
493
-				}
494
-			}
495
-		} else if ($shareType === self::SHARE_TYPE_GROUP) {
496
-			if (!\OC::$server->getGroupManager()->groupExists($shareWith)) {
497
-				$message = 'Sharing %s failed, because the group %s does not exist';
498
-				$message_t = $l->t('Sharing %s failed, because the group %s does not exist', array($itemSourceName, $shareWith));
499
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
500
-				throw new \Exception($message_t);
501
-			}
502
-			if ($shareWithinGroupOnly) {
503
-				$group = \OC::$server->getGroupManager()->get($shareWith);
504
-				$user = \OC::$server->getUserManager()->get($uidOwner);
505
-				if (!$group || !$user || !$group->inGroup($user)) {
506
-					$message = 'Sharing %s failed, because '
507
-						. '%s is not a member of the group %s';
508
-					$message_t = $l->t('Sharing %s failed, because %s is not a member of the group %s', array($itemSourceName, $uidOwner, $shareWith));
509
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), \OCP\Util::DEBUG);
510
-					throw new \Exception($message_t);
511
-				}
512
-			}
513
-			// Check if the item source is already shared with the group, either from the same owner or a different user
514
-			// The check for each user in the group is done inside the put() function
515
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
516
-				null, self::FORMAT_NONE, null, 1, true, true)) {
517
-
518
-				if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
519
-					$message = 'Sharing %s failed, because this item is already shared with %s';
520
-					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
521
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
522
-					throw new \Exception($message_t);
523
-				}
524
-			}
525
-			// Convert share with into an array with the keys group and users
526
-			$group = $shareWith;
527
-			$shareWith = array();
528
-			$shareWith['group'] = $group;
529
-
530
-
531
-			$groupObject = \OC::$server->getGroupManager()->get($group);
532
-			$userIds = [];
533
-			if ($groupObject) {
534
-				$users = $groupObject->searchUsers('', -1, 0);
535
-				foreach ($users as $user) {
536
-					$userIds[] = $user->getUID();
537
-				}
538
-			}
539
-
540
-			$shareWith['users'] = array_diff($userIds, array($uidOwner));
541
-		} else if ($shareType === self::SHARE_TYPE_LINK) {
542
-			$updateExistingShare = false;
543
-			if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
544
-
545
-				// IF the password is changed via the old ajax endpoint verify it before deleting the old share
546
-				if ($passwordChanged === true) {
547
-					self::verifyPassword($shareWith);
548
-				}
549
-
550
-				// when updating a link share
551
-				// FIXME Don't delete link if we update it
552
-				if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
553
-					$uidOwner, self::FORMAT_NONE, null, 1)) {
554
-					// remember old token
555
-					$oldToken = $checkExists['token'];
556
-					$oldPermissions = $checkExists['permissions'];
557
-					//delete the old share
558
-					Helper::delete($checkExists['id']);
559
-					$updateExistingShare = true;
560
-				}
561
-
562
-				if ($passwordChanged === null) {
563
-					// Generate hash of password - same method as user passwords
564
-					if (is_string($shareWith) && $shareWith !== '') {
565
-						self::verifyPassword($shareWith);
566
-						$shareWith = \OC::$server->getHasher()->hash($shareWith);
567
-					} else {
568
-						// reuse the already set password, but only if we change permissions
569
-						// otherwise the user disabled the password protection
570
-						if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
571
-							$shareWith = $checkExists['share_with'];
572
-						}
573
-					}
574
-				} else {
575
-					if ($passwordChanged === true) {
576
-						if (is_string($shareWith) && $shareWith !== '') {
577
-							self::verifyPassword($shareWith);
578
-							$shareWith = \OC::$server->getHasher()->hash($shareWith);
579
-						}
580
-					} else if ($updateExistingShare) {
581
-						$shareWith = $checkExists['share_with'];
582
-					}
583
-				}
584
-
585
-				if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
586
-					$message = 'You need to provide a password to create a public link, only protected links are allowed';
587
-					$message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
588
-					\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
589
-					throw new \Exception($message_t);
590
-				}
591
-
592
-				if ($updateExistingShare === false &&
593
-					self::isDefaultExpireDateEnabled() &&
594
-					empty($expirationDate)) {
595
-					$expirationDate = Helper::calcExpireDate();
596
-				}
597
-
598
-				// Generate token
599
-				if (isset($oldToken)) {
600
-					$token = $oldToken;
601
-				} else {
602
-					$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
603
-						\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
604
-					);
605
-				}
606
-				$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
607
-					null, $token, $itemSourceName, $expirationDate);
608
-				if ($result) {
609
-					return $token;
610
-				} else {
611
-					return false;
612
-				}
613
-			}
614
-			$message = 'Sharing %s failed, because sharing with links is not allowed';
615
-			$message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
616
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
617
-			throw new \Exception($message_t);
618
-		} else if ($shareType === self::SHARE_TYPE_REMOTE) {
619
-
620
-			/*
428
+                $expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
429
+            } catch (\Exception $e) {
430
+                throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
431
+            }
432
+        }
433
+
434
+        // Verify share type and sharing conditions are met
435
+        if ($shareType === self::SHARE_TYPE_USER) {
436
+            if ($shareWith == $uidOwner) {
437
+                $message = 'Sharing %s failed, because you can not share with yourself';
438
+                $message_t = $l->t('Sharing %s failed, because you can not share with yourself', [$itemName]);
439
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
440
+                throw new \Exception($message_t);
441
+            }
442
+            if (!\OC::$server->getUserManager()->userExists($shareWith)) {
443
+                $message = 'Sharing %s failed, because the user %s does not exist';
444
+                $message_t = $l->t('Sharing %s failed, because the user %s does not exist', array($itemSourceName, $shareWith));
445
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
446
+                throw new \Exception($message_t);
447
+            }
448
+            if ($shareWithinGroupOnly) {
449
+                $userManager = \OC::$server->getUserManager();
450
+                $groupManager = \OC::$server->getGroupManager();
451
+                $userOwner = $userManager->get($uidOwner);
452
+                $userShareWith = $userManager->get($shareWith);
453
+                $groupsOwner = [];
454
+                $groupsShareWith = [];
455
+                if ($userOwner) {
456
+                    $groupsOwner = $groupManager->getUserGroupIds($userOwner);
457
+                }
458
+                if ($userShareWith) {
459
+                    $groupsShareWith = $groupManager->getUserGroupIds($userShareWith);
460
+                }
461
+                $inGroup = array_intersect($groupsOwner, $groupsShareWith);
462
+                if (empty($inGroup)) {
463
+                    $message = 'Sharing %s failed, because the user '
464
+                        .'%s is not a member of any groups that %s is a member of';
465
+                    $message_t = $l->t('Sharing %s failed, because the user %s is not a member of any groups that %s is a member of', array($itemName, $shareWith, $uidOwner));
466
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemName, $shareWith, $uidOwner), \OCP\Util::DEBUG);
467
+                    throw new \Exception($message_t);
468
+                }
469
+            }
470
+            // Check if the item source is already shared with the user, either from the same owner or a different user
471
+            if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups,
472
+                $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
473
+                // Only allow the same share to occur again if it is the same
474
+                // owner and is not a user share, this use case is for increasing
475
+                // permissions for a specific user
476
+                if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
477
+                    $message = 'Sharing %s failed, because this item is already shared with %s';
478
+                    $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
479
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
480
+                    throw new \Exception($message_t);
481
+                }
482
+            }
483
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_USER,
484
+                $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
485
+                // Only allow the same share to occur again if it is the same
486
+                // owner and is not a user share, this use case is for increasing
487
+                // permissions for a specific user
488
+                if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
489
+                    $message = 'Sharing %s failed, because this item is already shared with user %s';
490
+                    $message_t = $l->t('Sharing %s failed, because this item is already shared with user %s', array($itemSourceName, $shareWith));
491
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::ERROR);
492
+                    throw new \Exception($message_t);
493
+                }
494
+            }
495
+        } else if ($shareType === self::SHARE_TYPE_GROUP) {
496
+            if (!\OC::$server->getGroupManager()->groupExists($shareWith)) {
497
+                $message = 'Sharing %s failed, because the group %s does not exist';
498
+                $message_t = $l->t('Sharing %s failed, because the group %s does not exist', array($itemSourceName, $shareWith));
499
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
500
+                throw new \Exception($message_t);
501
+            }
502
+            if ($shareWithinGroupOnly) {
503
+                $group = \OC::$server->getGroupManager()->get($shareWith);
504
+                $user = \OC::$server->getUserManager()->get($uidOwner);
505
+                if (!$group || !$user || !$group->inGroup($user)) {
506
+                    $message = 'Sharing %s failed, because '
507
+                        . '%s is not a member of the group %s';
508
+                    $message_t = $l->t('Sharing %s failed, because %s is not a member of the group %s', array($itemSourceName, $uidOwner, $shareWith));
509
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner, $shareWith), \OCP\Util::DEBUG);
510
+                    throw new \Exception($message_t);
511
+                }
512
+            }
513
+            // Check if the item source is already shared with the group, either from the same owner or a different user
514
+            // The check for each user in the group is done inside the put() function
515
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
516
+                null, self::FORMAT_NONE, null, 1, true, true)) {
517
+
518
+                if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
519
+                    $message = 'Sharing %s failed, because this item is already shared with %s';
520
+                    $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
521
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
522
+                    throw new \Exception($message_t);
523
+                }
524
+            }
525
+            // Convert share with into an array with the keys group and users
526
+            $group = $shareWith;
527
+            $shareWith = array();
528
+            $shareWith['group'] = $group;
529
+
530
+
531
+            $groupObject = \OC::$server->getGroupManager()->get($group);
532
+            $userIds = [];
533
+            if ($groupObject) {
534
+                $users = $groupObject->searchUsers('', -1, 0);
535
+                foreach ($users as $user) {
536
+                    $userIds[] = $user->getUID();
537
+                }
538
+            }
539
+
540
+            $shareWith['users'] = array_diff($userIds, array($uidOwner));
541
+        } else if ($shareType === self::SHARE_TYPE_LINK) {
542
+            $updateExistingShare = false;
543
+            if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
544
+
545
+                // IF the password is changed via the old ajax endpoint verify it before deleting the old share
546
+                if ($passwordChanged === true) {
547
+                    self::verifyPassword($shareWith);
548
+                }
549
+
550
+                // when updating a link share
551
+                // FIXME Don't delete link if we update it
552
+                if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
553
+                    $uidOwner, self::FORMAT_NONE, null, 1)) {
554
+                    // remember old token
555
+                    $oldToken = $checkExists['token'];
556
+                    $oldPermissions = $checkExists['permissions'];
557
+                    //delete the old share
558
+                    Helper::delete($checkExists['id']);
559
+                    $updateExistingShare = true;
560
+                }
561
+
562
+                if ($passwordChanged === null) {
563
+                    // Generate hash of password - same method as user passwords
564
+                    if (is_string($shareWith) && $shareWith !== '') {
565
+                        self::verifyPassword($shareWith);
566
+                        $shareWith = \OC::$server->getHasher()->hash($shareWith);
567
+                    } else {
568
+                        // reuse the already set password, but only if we change permissions
569
+                        // otherwise the user disabled the password protection
570
+                        if ($checkExists && (int)$permissions !== (int)$oldPermissions) {
571
+                            $shareWith = $checkExists['share_with'];
572
+                        }
573
+                    }
574
+                } else {
575
+                    if ($passwordChanged === true) {
576
+                        if (is_string($shareWith) && $shareWith !== '') {
577
+                            self::verifyPassword($shareWith);
578
+                            $shareWith = \OC::$server->getHasher()->hash($shareWith);
579
+                        }
580
+                    } else if ($updateExistingShare) {
581
+                        $shareWith = $checkExists['share_with'];
582
+                    }
583
+                }
584
+
585
+                if (\OCP\Util::isPublicLinkPasswordRequired() && empty($shareWith)) {
586
+                    $message = 'You need to provide a password to create a public link, only protected links are allowed';
587
+                    $message_t = $l->t('You need to provide a password to create a public link, only protected links are allowed');
588
+                    \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
589
+                    throw new \Exception($message_t);
590
+                }
591
+
592
+                if ($updateExistingShare === false &&
593
+                    self::isDefaultExpireDateEnabled() &&
594
+                    empty($expirationDate)) {
595
+                    $expirationDate = Helper::calcExpireDate();
596
+                }
597
+
598
+                // Generate token
599
+                if (isset($oldToken)) {
600
+                    $token = $oldToken;
601
+                } else {
602
+                    $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH,
603
+                        \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
604
+                    );
605
+                }
606
+                $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions,
607
+                    null, $token, $itemSourceName, $expirationDate);
608
+                if ($result) {
609
+                    return $token;
610
+                } else {
611
+                    return false;
612
+                }
613
+            }
614
+            $message = 'Sharing %s failed, because sharing with links is not allowed';
615
+            $message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
616
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
617
+            throw new \Exception($message_t);
618
+        } else if ($shareType === self::SHARE_TYPE_REMOTE) {
619
+
620
+            /*
621 621
 			 * Check if file is not already shared with the remote user
622 622
 			 */
623
-			if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
624
-				$shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
625
-					$message = 'Sharing %s failed, because this item is already shared with %s';
626
-					$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
627
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
628
-					throw new \Exception($message_t);
629
-			}
630
-
631
-			// don't allow federated shares if source and target server are the same
632
-			list($user, $remote) = Helper::splitUserRemote($shareWith);
633
-			$currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
634
-			$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
635
-			if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
636
-				$message = 'Not allowed to create a federated share with the same user.';
637
-				$message_t = $l->t('Not allowed to create a federated share with the same user');
638
-				\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
639
-				throw new \Exception($message_t);
640
-			}
641
-
642
-			$token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
643
-				\OCP\Security\ISecureRandom::CHAR_DIGITS);
644
-
645
-			$shareWith = $user . '@' . $remote;
646
-			$shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
647
-
648
-			$send = false;
649
-			if ($shareId) {
650
-				$send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
651
-			}
652
-
653
-			if ($send === false) {
654
-				$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
655
-				self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
656
-				$message_t = $l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
657
-				throw new \Exception($message_t);
658
-			}
659
-
660
-			return $send;
661
-		} else {
662
-			// Future share types need to include their own conditions
663
-			$message = 'Share type %s is not valid for %s';
664
-			$message_t = $l->t('Share type %s is not valid for %s', array($shareType, $itemSource));
665
-			\OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), \OCP\Util::DEBUG);
666
-			throw new \Exception($message_t);
667
-		}
668
-
669
-		// Put the item into the database
670
-		$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
671
-
672
-		return $result ? true : false;
673
-	}
674
-
675
-	/**
676
-	 * Unshare an item from a user, group, or delete a private link
677
-	 * @param string $itemType
678
-	 * @param string $itemSource
679
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
680
-	 * @param string $shareWith User or group the item is being shared with
681
-	 * @param string $owner owner of the share, if null the current user is used
682
-	 * @return boolean true on success or false on failure
683
-	 */
684
-	public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
685
-
686
-		// check if it is a valid itemType
687
-		self::getBackend($itemType);
688
-
689
-		$items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
690
-
691
-		$toDelete = array();
692
-		$newParent = null;
693
-		$currentUser = $owner ? $owner : \OC_User::getUser();
694
-		foreach ($items as $item) {
695
-			// delete the item with the expected share_type and owner
696
-			if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
697
-				$toDelete = $item;
698
-				// if there is more then one result we don't have to delete the children
699
-				// but update their parent. For group shares the new parent should always be
700
-				// the original group share and not the db entry with the unique name
701
-			} else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
702
-				$newParent = $item['parent'];
703
-			} else {
704
-				$newParent = $item['id'];
705
-			}
706
-		}
707
-
708
-		if (!empty($toDelete)) {
709
-			self::unshareItem($toDelete, $newParent);
710
-			return true;
711
-		}
712
-		return false;
713
-	}
714
-
715
-	/**
716
-	 * sent status if users got informed by mail about share
717
-	 * @param string $itemType
718
-	 * @param string $itemSource
719
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
720
-	 * @param string $recipient with whom was the file shared
721
-	 * @param boolean $status
722
-	 */
723
-	public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
724
-		$status = $status ? 1 : 0;
725
-
726
-		$query = \OC_DB::prepare(
727
-			'UPDATE `*PREFIX*share`
623
+            if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_REMOTE,
624
+                $shareWith, $uidOwner, self::FORMAT_NONE, null, 1, true, true)) {
625
+                    $message = 'Sharing %s failed, because this item is already shared with %s';
626
+                    $message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
627
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
628
+                    throw new \Exception($message_t);
629
+            }
630
+
631
+            // don't allow federated shares if source and target server are the same
632
+            list($user, $remote) = Helper::splitUserRemote($shareWith);
633
+            $currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
634
+            $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
635
+            if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
636
+                $message = 'Not allowed to create a federated share with the same user.';
637
+                $message_t = $l->t('Not allowed to create a federated share with the same user');
638
+                \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
639
+                throw new \Exception($message_t);
640
+            }
641
+
642
+            $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
643
+                \OCP\Security\ISecureRandom::CHAR_DIGITS);
644
+
645
+            $shareWith = $user . '@' . $remote;
646
+            $shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
647
+
648
+            $send = false;
649
+            if ($shareId) {
650
+                $send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
651
+            }
652
+
653
+            if ($send === false) {
654
+                $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
655
+                self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
656
+                $message_t = $l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
657
+                throw new \Exception($message_t);
658
+            }
659
+
660
+            return $send;
661
+        } else {
662
+            // Future share types need to include their own conditions
663
+            $message = 'Share type %s is not valid for %s';
664
+            $message_t = $l->t('Share type %s is not valid for %s', array($shareType, $itemSource));
665
+            \OCP\Util::writeLog('OCP\Share', sprintf($message, $shareType, $itemSource), \OCP\Util::DEBUG);
666
+            throw new \Exception($message_t);
667
+        }
668
+
669
+        // Put the item into the database
670
+        $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
671
+
672
+        return $result ? true : false;
673
+    }
674
+
675
+    /**
676
+     * Unshare an item from a user, group, or delete a private link
677
+     * @param string $itemType
678
+     * @param string $itemSource
679
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
680
+     * @param string $shareWith User or group the item is being shared with
681
+     * @param string $owner owner of the share, if null the current user is used
682
+     * @return boolean true on success or false on failure
683
+     */
684
+    public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
685
+
686
+        // check if it is a valid itemType
687
+        self::getBackend($itemType);
688
+
689
+        $items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
690
+
691
+        $toDelete = array();
692
+        $newParent = null;
693
+        $currentUser = $owner ? $owner : \OC_User::getUser();
694
+        foreach ($items as $item) {
695
+            // delete the item with the expected share_type and owner
696
+            if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
697
+                $toDelete = $item;
698
+                // if there is more then one result we don't have to delete the children
699
+                // but update their parent. For group shares the new parent should always be
700
+                // the original group share and not the db entry with the unique name
701
+            } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
702
+                $newParent = $item['parent'];
703
+            } else {
704
+                $newParent = $item['id'];
705
+            }
706
+        }
707
+
708
+        if (!empty($toDelete)) {
709
+            self::unshareItem($toDelete, $newParent);
710
+            return true;
711
+        }
712
+        return false;
713
+    }
714
+
715
+    /**
716
+     * sent status if users got informed by mail about share
717
+     * @param string $itemType
718
+     * @param string $itemSource
719
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
720
+     * @param string $recipient with whom was the file shared
721
+     * @param boolean $status
722
+     */
723
+    public static function setSendMailStatus($itemType, $itemSource, $shareType, $recipient, $status) {
724
+        $status = $status ? 1 : 0;
725
+
726
+        $query = \OC_DB::prepare(
727
+            'UPDATE `*PREFIX*share`
728 728
 					SET `mail_send` = ?
729 729
 					WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?');
730 730
 
731
-		$result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
732
-
733
-		if($result === false) {
734
-			\OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', \OCP\Util::ERROR);
735
-		}
736
-	}
737
-
738
-	/**
739
-	 * validate expiration date if it meets all constraints
740
-	 *
741
-	 * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
742
-	 * @param string $shareTime timestamp when the file was shared
743
-	 * @param string $itemType
744
-	 * @param string $itemSource
745
-	 * @return \DateTime validated date
746
-	 * @throws \Exception when the expire date is in the past or further in the future then the enforced date
747
-	 */
748
-	private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
749
-		$l = \OC::$server->getL10N('lib');
750
-		$date = new \DateTime($expireDate);
751
-		$today = new \DateTime('now');
752
-
753
-		// if the user doesn't provide a share time we need to get it from the database
754
-		// fall-back mode to keep API stable, because the $shareTime parameter was added later
755
-		$defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
756
-		if ($defaultExpireDateEnforced && $shareTime === null) {
757
-			$items = self::getItemShared($itemType, $itemSource);
758
-			$firstItem = reset($items);
759
-			$shareTime = (int)$firstItem['stime'];
760
-		}
761
-
762
-		if ($defaultExpireDateEnforced) {
763
-			// initialize max date with share time
764
-			$maxDate = new \DateTime();
765
-			$maxDate->setTimestamp($shareTime);
766
-			$maxDays = \OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
767
-			$maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
768
-			if ($date > $maxDate) {
769
-				$warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
770
-				$warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
771
-				\OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
772
-				throw new \Exception($warning_t);
773
-			}
774
-		}
775
-
776
-		if ($date < $today) {
777
-			$message = 'Cannot set expiration date. Expiration date is in the past';
778
-			$message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
779
-			\OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::WARN);
780
-			throw new \Exception($message_t);
781
-		}
782
-
783
-		return $date;
784
-	}
785
-
786
-	/**
787
-	 * Checks whether a share has expired, calls unshareItem() if yes.
788
-	 * @param array $item Share data (usually database row)
789
-	 * @return boolean True if item was expired, false otherwise.
790
-	 */
791
-	protected static function expireItem(array $item) {
792
-
793
-		$result = false;
794
-
795
-		// only use default expiration date for link shares
796
-		if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
797
-
798
-			// calculate expiration date
799
-			if (!empty($item['expiration'])) {
800
-				$userDefinedExpire = new \DateTime($item['expiration']);
801
-				$expires = $userDefinedExpire->getTimestamp();
802
-			} else {
803
-				$expires = null;
804
-			}
805
-
806
-
807
-			// get default expiration settings
808
-			$defaultSettings = Helper::getDefaultExpireSetting();
809
-			$expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
810
-
811
-
812
-			if (is_int($expires)) {
813
-				$now = time();
814
-				if ($now > $expires) {
815
-					self::unshareItem($item);
816
-					$result = true;
817
-				}
818
-			}
819
-		}
820
-		return $result;
821
-	}
822
-
823
-	/**
824
-	 * Unshares a share given a share data array
825
-	 * @param array $item Share data (usually database row)
826
-	 * @param int $newParent parent ID
827
-	 * @return null
828
-	 */
829
-	protected static function unshareItem(array $item, $newParent = null) {
830
-
831
-		$shareType = (int)$item['share_type'];
832
-		$shareWith = null;
833
-		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
834
-			$shareWith = $item['share_with'];
835
-		}
836
-
837
-		// Pass all the vars we have for now, they may be useful
838
-		$hookParams = array(
839
-			'id'            => $item['id'],
840
-			'itemType'      => $item['item_type'],
841
-			'itemSource'    => $item['item_source'],
842
-			'shareType'     => $shareType,
843
-			'shareWith'     => $shareWith,
844
-			'itemParent'    => $item['parent'],
845
-			'uidOwner'      => $item['uid_owner'],
846
-		);
847
-		if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
848
-			$hookParams['fileSource'] = $item['file_source'];
849
-			$hookParams['fileTarget'] = $item['file_target'];
850
-		}
851
-
852
-		\OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
853
-		$deletedShares = Helper::delete($item['id'], false, null, $newParent);
854
-		$deletedShares[] = $hookParams;
855
-		$hookParams['deletedShares'] = $deletedShares;
856
-		\OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
857
-		if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
858
-			list(, $remote) = Helper::splitUserRemote($item['share_with']);
859
-			self::sendRemoteUnshare($remote, $item['id'], $item['token']);
860
-		}
861
-	}
862
-
863
-	/**
864
-	 * Get the backend class for the specified item type
865
-	 * @param string $itemType
866
-	 * @throws \Exception
867
-	 * @return \OCP\Share_Backend
868
-	 */
869
-	public static function getBackend($itemType) {
870
-		$l = \OC::$server->getL10N('lib');
871
-		if (isset(self::$backends[$itemType])) {
872
-			return self::$backends[$itemType];
873
-		} else if (isset(self::$backendTypes[$itemType]['class'])) {
874
-			$class = self::$backendTypes[$itemType]['class'];
875
-			if (class_exists($class)) {
876
-				self::$backends[$itemType] = new $class;
877
-				if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
878
-					$message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
879
-					$message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
880
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
881
-					throw new \Exception($message_t);
882
-				}
883
-				return self::$backends[$itemType];
884
-			} else {
885
-				$message = 'Sharing backend %s not found';
886
-				$message_t = $l->t('Sharing backend %s not found', array($class));
887
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
888
-				throw new \Exception($message_t);
889
-			}
890
-		}
891
-		$message = 'Sharing backend for %s not found';
892
-		$message_t = $l->t('Sharing backend for %s not found', array($itemType));
893
-		\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), \OCP\Util::ERROR);
894
-		throw new \Exception($message_t);
895
-	}
896
-
897
-	/**
898
-	 * Check if resharing is allowed
899
-	 * @return boolean true if allowed or false
900
-	 *
901
-	 * Resharing is allowed by default if not configured
902
-	 */
903
-	public static function isResharingAllowed() {
904
-		if (!isset(self::$isResharingAllowed)) {
905
-			if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
906
-				self::$isResharingAllowed = true;
907
-			} else {
908
-				self::$isResharingAllowed = false;
909
-			}
910
-		}
911
-		return self::$isResharingAllowed;
912
-	}
913
-
914
-	/**
915
-	 * Get a list of collection item types for the specified item type
916
-	 * @param string $itemType
917
-	 * @return array
918
-	 */
919
-	private static function getCollectionItemTypes($itemType) {
920
-		$collectionTypes = array($itemType);
921
-		foreach (self::$backendTypes as $type => $backend) {
922
-			if (in_array($backend['collectionOf'], $collectionTypes)) {
923
-				$collectionTypes[] = $type;
924
-			}
925
-		}
926
-		// TODO Add option for collections to be collection of themselves, only 'folder' does it now...
927
-		if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
928
-			unset($collectionTypes[0]);
929
-		}
930
-		// Return array if collections were found or the item type is a
931
-		// collection itself - collections can be inside collections
932
-		if (count($collectionTypes) > 0) {
933
-			return $collectionTypes;
934
-		}
935
-		return false;
936
-	}
937
-
938
-	/**
939
-	 * Get the owners of items shared with a user.
940
-	 *
941
-	 * @param string $user The user the items are shared with.
942
-	 * @param string $type The type of the items shared with the user.
943
-	 * @param boolean $includeCollections Include collection item types (optional)
944
-	 * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
945
-	 * @return array
946
-	 */
947
-	public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
948
-		// First, we find out if $type is part of a collection (and if that collection is part of
949
-		// another one and so on).
950
-		$collectionTypes = array();
951
-		if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
952
-			$collectionTypes[] = $type;
953
-		}
954
-
955
-		// Of these collection types, along with our original $type, we make a
956
-		// list of the ones for which a sharing backend has been registered.
957
-		// FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
958
-		// with its $includeCollections parameter set to true. Unfortunately, this fails currently.
959
-		$allMaybeSharedItems = array();
960
-		foreach ($collectionTypes as $collectionType) {
961
-			if (isset(self::$backends[$collectionType])) {
962
-				$allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
963
-					$collectionType,
964
-					$user,
965
-					self::FORMAT_NONE
966
-				);
967
-			}
968
-		}
969
-
970
-		$owners = array();
971
-		if ($includeOwner) {
972
-			$owners[] = $user;
973
-		}
974
-
975
-		// We take a look at all shared items of the given $type (or of the collections it is part of)
976
-		// and find out their owners. Then, we gather the tags for the original $type from all owners,
977
-		// and return them as elements of a list that look like "Tag (owner)".
978
-		foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
979
-			foreach ($maybeSharedItems as $sharedItem) {
980
-				if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
981
-					$owners[] = $sharedItem['uid_owner'];
982
-				}
983
-			}
984
-		}
985
-
986
-		return $owners;
987
-	}
988
-
989
-	/**
990
-	 * Get shared items from the database
991
-	 * @param string $itemType
992
-	 * @param string $item Item source or target (optional)
993
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
994
-	 * @param string $shareWith User or group the item is being shared with
995
-	 * @param string $uidOwner User that is the owner of shared items (optional)
996
-	 * @param int $format Format to convert items to with formatItems() (optional)
997
-	 * @param mixed $parameters to pass to formatItems() (optional)
998
-	 * @param int $limit Number of items to return, -1 to return all matches (optional)
999
-	 * @param boolean $includeCollections Include collection item types (optional)
1000
-	 * @param boolean $itemShareWithBySource (optional)
1001
-	 * @param boolean $checkExpireDate
1002
-	 * @return array
1003
-	 *
1004
-	 * See public functions getItem(s)... for parameter usage
1005
-	 *
1006
-	 */
1007
-	public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
1008
-									$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
1009
-									$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
1010
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
1011
-			return array();
1012
-		}
1013
-		$backend = self::getBackend($itemType);
1014
-		$collectionTypes = false;
1015
-		// Get filesystem root to add it to the file target and remove from the
1016
-		// file source, match file_source with the file cache
1017
-		if ($itemType == 'file' || $itemType == 'folder') {
1018
-			if(!is_null($uidOwner)) {
1019
-				$root = \OC\Files\Filesystem::getRoot();
1020
-			} else {
1021
-				$root = '';
1022
-			}
1023
-			$where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
1024
-			if (!isset($item)) {
1025
-				$where .= ' AND `file_target` IS NOT NULL ';
1026
-			}
1027
-			$where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
1028
-			$fileDependent = true;
1029
-			$queryArgs = array();
1030
-		} else {
1031
-			$fileDependent = false;
1032
-			$root = '';
1033
-			$collectionTypes = self::getCollectionItemTypes($itemType);
1034
-			if ($includeCollections && !isset($item) && $collectionTypes) {
1035
-				// If includeCollections is true, find collections of this item type, e.g. a music album contains songs
1036
-				if (!in_array($itemType, $collectionTypes)) {
1037
-					$itemTypes = array_merge(array($itemType), $collectionTypes);
1038
-				} else {
1039
-					$itemTypes = $collectionTypes;
1040
-				}
1041
-				$placeholders = join(',', array_fill(0, count($itemTypes), '?'));
1042
-				$where = ' WHERE `item_type` IN ('.$placeholders.'))';
1043
-				$queryArgs = $itemTypes;
1044
-			} else {
1045
-				$where = ' WHERE `item_type` = ?';
1046
-				$queryArgs = array($itemType);
1047
-			}
1048
-		}
1049
-		if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1050
-			$where .= ' AND `share_type` != ?';
1051
-			$queryArgs[] = self::SHARE_TYPE_LINK;
1052
-		}
1053
-		if (isset($shareType)) {
1054
-			// Include all user and group items
1055
-			if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
1056
-				$where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
1057
-				$queryArgs[] = self::SHARE_TYPE_USER;
1058
-				$queryArgs[] = self::$shareTypeGroupUserUnique;
1059
-				$queryArgs[] = $shareWith;
1060
-
1061
-				$user = \OC::$server->getUserManager()->get($shareWith);
1062
-				$groups = [];
1063
-				if ($user) {
1064
-					$groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
1065
-				}
1066
-				if (!empty($groups)) {
1067
-					$placeholders = join(',', array_fill(0, count($groups), '?'));
1068
-					$where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
1069
-					$queryArgs[] = self::SHARE_TYPE_GROUP;
1070
-					$queryArgs = array_merge($queryArgs, $groups);
1071
-				}
1072
-				$where .= ')';
1073
-				// Don't include own group shares
1074
-				$where .= ' AND `uid_owner` != ?';
1075
-				$queryArgs[] = $shareWith;
1076
-			} else {
1077
-				$where .= ' AND `share_type` = ?';
1078
-				$queryArgs[] = $shareType;
1079
-				if (isset($shareWith)) {
1080
-					$where .= ' AND `share_with` = ?';
1081
-					$queryArgs[] = $shareWith;
1082
-				}
1083
-			}
1084
-		}
1085
-		if (isset($uidOwner)) {
1086
-			$where .= ' AND `uid_owner` = ?';
1087
-			$queryArgs[] = $uidOwner;
1088
-			if (!isset($shareType)) {
1089
-				// Prevent unique user targets for group shares from being selected
1090
-				$where .= ' AND `share_type` != ?';
1091
-				$queryArgs[] = self::$shareTypeGroupUserUnique;
1092
-			}
1093
-			if ($fileDependent) {
1094
-				$column = 'file_source';
1095
-			} else {
1096
-				$column = 'item_source';
1097
-			}
1098
-		} else {
1099
-			if ($fileDependent) {
1100
-				$column = 'file_target';
1101
-			} else {
1102
-				$column = 'item_target';
1103
-			}
1104
-		}
1105
-		if (isset($item)) {
1106
-			$collectionTypes = self::getCollectionItemTypes($itemType);
1107
-			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1108
-				$where .= ' AND (';
1109
-			} else {
1110
-				$where .= ' AND';
1111
-			}
1112
-			// If looking for own shared items, check item_source else check item_target
1113
-			if (isset($uidOwner) || $itemShareWithBySource) {
1114
-				// If item type is a file, file source needs to be checked in case the item was converted
1115
-				if ($fileDependent) {
1116
-					$where .= ' `file_source` = ?';
1117
-					$column = 'file_source';
1118
-				} else {
1119
-					$where .= ' `item_source` = ?';
1120
-					$column = 'item_source';
1121
-				}
1122
-			} else {
1123
-				if ($fileDependent) {
1124
-					$where .= ' `file_target` = ?';
1125
-					$item = \OC\Files\Filesystem::normalizePath($item);
1126
-				} else {
1127
-					$where .= ' `item_target` = ?';
1128
-				}
1129
-			}
1130
-			$queryArgs[] = $item;
1131
-			if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1132
-				$placeholders = join(',', array_fill(0, count($collectionTypes), '?'));
1133
-				$where .= ' OR `item_type` IN ('.$placeholders.'))';
1134
-				$queryArgs = array_merge($queryArgs, $collectionTypes);
1135
-			}
1136
-		}
1137
-
1138
-		if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
1139
-			// Make sure the unique user target is returned if it exists,
1140
-			// unique targets should follow the group share in the database
1141
-			// If the limit is not 1, the filtering can be done later
1142
-			$where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
1143
-		} else {
1144
-			$where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
1145
-		}
1146
-
1147
-		if ($limit != -1 && !$includeCollections) {
1148
-			// The limit must be at least 3, because filtering needs to be done
1149
-			if ($limit < 3) {
1150
-				$queryLimit = 3;
1151
-			} else {
1152
-				$queryLimit = $limit;
1153
-			}
1154
-		} else {
1155
-			$queryLimit = null;
1156
-		}
1157
-		$select = self::createSelectStatement($format, $fileDependent, $uidOwner);
1158
-		$root = strlen($root);
1159
-		$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
1160
-		$result = $query->execute($queryArgs);
1161
-		if ($result === false) {
1162
-			\OCP\Util::writeLog('OCP\Share',
1163
-				\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
1164
-				\OCP\Util::ERROR);
1165
-		}
1166
-		$items = array();
1167
-		$targets = array();
1168
-		$switchedItems = array();
1169
-		$mounts = array();
1170
-		while ($row = $result->fetchRow()) {
1171
-			self::transformDBResults($row);
1172
-			// Filter out duplicate group shares for users with unique targets
1173
-			if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
1174
-				continue;
1175
-			}
1176
-			if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
1177
-				$row['share_type'] = self::SHARE_TYPE_GROUP;
1178
-				$row['unique_name'] = true; // remember that we use a unique name for this user
1179
-				$row['share_with'] = $items[$row['parent']]['share_with'];
1180
-				// if the group share was unshared from the user we keep the permission, otherwise
1181
-				// we take the permission from the parent because this is always the up-to-date
1182
-				// permission for the group share
1183
-				if ($row['permissions'] > 0) {
1184
-					$row['permissions'] = $items[$row['parent']]['permissions'];
1185
-				}
1186
-				// Remove the parent group share
1187
-				unset($items[$row['parent']]);
1188
-				if ($row['permissions'] == 0) {
1189
-					continue;
1190
-				}
1191
-			} else if (!isset($uidOwner)) {
1192
-				// Check if the same target already exists
1193
-				if (isset($targets[$row['id']])) {
1194
-					// Check if the same owner shared with the user twice
1195
-					// through a group and user share - this is allowed
1196
-					$id = $targets[$row['id']];
1197
-					if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
1198
-						// Switch to group share type to ensure resharing conditions aren't bypassed
1199
-						if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
1200
-							$items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
1201
-							$items[$id]['share_with'] = $row['share_with'];
1202
-						}
1203
-						// Switch ids if sharing permission is granted on only
1204
-						// one share to ensure correct parent is used if resharing
1205
-						if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
1206
-							&& (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1207
-							$items[$row['id']] = $items[$id];
1208
-							$switchedItems[$id] = $row['id'];
1209
-							unset($items[$id]);
1210
-							$id = $row['id'];
1211
-						}
1212
-						$items[$id]['permissions'] |= (int)$row['permissions'];
1213
-
1214
-					}
1215
-					continue;
1216
-				} elseif (!empty($row['parent'])) {
1217
-					$targets[$row['parent']] = $row['id'];
1218
-				}
1219
-			}
1220
-			// Remove root from file source paths if retrieving own shared items
1221
-			if (isset($uidOwner) && isset($row['path'])) {
1222
-				if (isset($row['parent'])) {
1223
-					$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
1224
-					$parentResult = $query->execute(array($row['parent']));
1225
-					if ($result === false) {
1226
-						\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
1227
-							\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
1228
-							\OCP\Util::ERROR);
1229
-					} else {
1230
-						$parentRow = $parentResult->fetchRow();
1231
-						$tmpPath = $parentRow['file_target'];
1232
-						// find the right position where the row path continues from the target path
1233
-						$pos = strrpos($row['path'], $parentRow['file_target']);
1234
-						$subPath = substr($row['path'], $pos);
1235
-						$splitPath = explode('/', $subPath);
1236
-						foreach (array_slice($splitPath, 2) as $pathPart) {
1237
-							$tmpPath = $tmpPath . '/' . $pathPart;
1238
-						}
1239
-						$row['path'] = $tmpPath;
1240
-					}
1241
-				} else {
1242
-					if (!isset($mounts[$row['storage']])) {
1243
-						$mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
1244
-						if (is_array($mountPoints) && !empty($mountPoints)) {
1245
-							$mounts[$row['storage']] = current($mountPoints);
1246
-						}
1247
-					}
1248
-					if (!empty($mounts[$row['storage']])) {
1249
-						$path = $mounts[$row['storage']]->getMountPoint().$row['path'];
1250
-						$relPath = substr($path, $root); // path relative to data/user
1251
-						$row['path'] = rtrim($relPath, '/');
1252
-					}
1253
-				}
1254
-			}
1255
-
1256
-			if($checkExpireDate) {
1257
-				if (self::expireItem($row)) {
1258
-					continue;
1259
-				}
1260
-			}
1261
-			// Check if resharing is allowed, if not remove share permission
1262
-			if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
1263
-				$row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
1264
-			}
1265
-			// Add display names to result
1266
-			$row['share_with_displayname'] = $row['share_with'];
1267
-			if ( isset($row['share_with']) && $row['share_with'] != '' &&
1268
-				$row['share_type'] === self::SHARE_TYPE_USER) {
1269
-				$row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']);
1270
-			} else if(isset($row['share_with']) && $row['share_with'] != '' &&
1271
-				$row['share_type'] === self::SHARE_TYPE_REMOTE) {
1272
-				$addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
1273
-				foreach ($addressBookEntries as $entry) {
1274
-					foreach ($entry['CLOUD'] as $cloudID) {
1275
-						if ($cloudID === $row['share_with']) {
1276
-							$row['share_with_displayname'] = $entry['FN'];
1277
-						}
1278
-					}
1279
-				}
1280
-			}
1281
-			if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
1282
-				$row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']);
1283
-			}
1284
-
1285
-			if ($row['permissions'] > 0) {
1286
-				$items[$row['id']] = $row;
1287
-			}
1288
-
1289
-		}
1290
-
1291
-		// group items if we are looking for items shared with the current user
1292
-		if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
1293
-			$items = self::groupItems($items, $itemType);
1294
-		}
1295
-
1296
-		if (!empty($items)) {
1297
-			$collectionItems = array();
1298
-			foreach ($items as &$row) {
1299
-				// Return only the item instead of a 2-dimensional array
1300
-				if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
1301
-					if ($format == self::FORMAT_NONE) {
1302
-						return $row;
1303
-					} else {
1304
-						break;
1305
-					}
1306
-				}
1307
-				// Check if this is a collection of the requested item type
1308
-				if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
1309
-					if (($collectionBackend = self::getBackend($row['item_type']))
1310
-						&& $collectionBackend instanceof \OCP\Share_Backend_Collection) {
1311
-						// Collections can be inside collections, check if the item is a collection
1312
-						if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
1313
-							$collectionItems[] = $row;
1314
-						} else {
1315
-							$collection = array();
1316
-							$collection['item_type'] = $row['item_type'];
1317
-							if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1318
-								$collection['path'] = basename($row['path']);
1319
-							}
1320
-							$row['collection'] = $collection;
1321
-							// Fetch all of the children sources
1322
-							$children = $collectionBackend->getChildren($row[$column]);
1323
-							foreach ($children as $child) {
1324
-								$childItem = $row;
1325
-								$childItem['item_type'] = $itemType;
1326
-								if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
1327
-									$childItem['item_source'] = $child['source'];
1328
-									$childItem['item_target'] = $child['target'];
1329
-								}
1330
-								if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1331
-									if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1332
-										$childItem['file_source'] = $child['source'];
1333
-									} else { // TODO is this really needed if we already know that we use the file backend?
1334
-										$meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
1335
-										$childItem['file_source'] = $meta['fileid'];
1336
-									}
1337
-									$childItem['file_target'] =
1338
-										\OC\Files\Filesystem::normalizePath($child['file_path']);
1339
-								}
1340
-								if (isset($item)) {
1341
-									if ($childItem[$column] == $item) {
1342
-										// Return only the item instead of a 2-dimensional array
1343
-										if ($limit == 1) {
1344
-											if ($format == self::FORMAT_NONE) {
1345
-												return $childItem;
1346
-											} else {
1347
-												// Unset the items array and break out of both loops
1348
-												$items = array();
1349
-												$items[] = $childItem;
1350
-												break 2;
1351
-											}
1352
-										} else {
1353
-											$collectionItems[] = $childItem;
1354
-										}
1355
-									}
1356
-								} else {
1357
-									$collectionItems[] = $childItem;
1358
-								}
1359
-							}
1360
-						}
1361
-					}
1362
-					// Remove collection item
1363
-					$toRemove = $row['id'];
1364
-					if (array_key_exists($toRemove, $switchedItems)) {
1365
-						$toRemove = $switchedItems[$toRemove];
1366
-					}
1367
-					unset($items[$toRemove]);
1368
-				} elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
1369
-					// FIXME: Thats a dirty hack to improve file sharing performance,
1370
-					// see github issue #10588 for more details
1371
-					// Need to find a solution which works for all back-ends
1372
-					$collectionBackend = self::getBackend($row['item_type']);
1373
-					$sharedParents = $collectionBackend->getParents($row['item_source']);
1374
-					foreach ($sharedParents as $parent) {
1375
-						$collectionItems[] = $parent;
1376
-					}
1377
-				}
1378
-			}
1379
-			if (!empty($collectionItems)) {
1380
-				$collectionItems = array_unique($collectionItems, SORT_REGULAR);
1381
-				$items = array_merge($items, $collectionItems);
1382
-			}
1383
-
1384
-			// filter out invalid items, these can appear when subshare entries exist
1385
-			// for a group in which the requested user isn't a member any more
1386
-			$items = array_filter($items, function($item) {
1387
-				return $item['share_type'] !== self::$shareTypeGroupUserUnique;
1388
-			});
1389
-
1390
-			return self::formatResult($items, $column, $backend, $format, $parameters);
1391
-		} elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
1392
-			// FIXME: Thats a dirty hack to improve file sharing performance,
1393
-			// see github issue #10588 for more details
1394
-			// Need to find a solution which works for all back-ends
1395
-			$collectionItems = array();
1396
-			$collectionBackend = self::getBackend('folder');
1397
-			$sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
1398
-			foreach ($sharedParents as $parent) {
1399
-				$collectionItems[] = $parent;
1400
-			}
1401
-			if ($limit === 1) {
1402
-				return reset($collectionItems);
1403
-			}
1404
-			return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
1405
-		}
1406
-
1407
-		return array();
1408
-	}
1409
-
1410
-	/**
1411
-	 * group items with link to the same source
1412
-	 *
1413
-	 * @param array $items
1414
-	 * @param string $itemType
1415
-	 * @return array of grouped items
1416
-	 */
1417
-	protected static function groupItems($items, $itemType) {
1418
-
1419
-		$fileSharing = $itemType === 'file' || $itemType === 'folder';
1420
-
1421
-		$result = array();
1422
-
1423
-		foreach ($items as $item) {
1424
-			$grouped = false;
1425
-			foreach ($result as $key => $r) {
1426
-				// for file/folder shares we need to compare file_source, otherwise we compare item_source
1427
-				// only group shares if they already point to the same target, otherwise the file where shared
1428
-				// before grouping of shares was added. In this case we don't group them toi avoid confusions
1429
-				if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
1430
-					(!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
1431
-					// add the first item to the list of grouped shares
1432
-					if (!isset($result[$key]['grouped'])) {
1433
-						$result[$key]['grouped'][] = $result[$key];
1434
-					}
1435
-					$result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
1436
-					$result[$key]['grouped'][] = $item;
1437
-					$grouped = true;
1438
-					break;
1439
-				}
1440
-			}
1441
-
1442
-			if (!$grouped) {
1443
-				$result[] = $item;
1444
-			}
1445
-
1446
-		}
1447
-
1448
-		return $result;
1449
-	}
1450
-
1451
-	/**
1452
-	 * Put shared item into the database
1453
-	 * @param string $itemType Item type
1454
-	 * @param string $itemSource Item source
1455
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1456
-	 * @param string $shareWith User or group the item is being shared with
1457
-	 * @param string $uidOwner User that is the owner of shared item
1458
-	 * @param int $permissions CRUDS permissions
1459
-	 * @param boolean|array $parentFolder Parent folder target (optional)
1460
-	 * @param string $token (optional)
1461
-	 * @param string $itemSourceName name of the source item (optional)
1462
-	 * @param \DateTime $expirationDate (optional)
1463
-	 * @throws \Exception
1464
-	 * @return mixed id of the new share or false
1465
-	 */
1466
-	private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1467
-								$permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
1468
-
1469
-		$queriesToExecute = array();
1470
-		$suggestedItemTarget = null;
1471
-		$groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
1472
-		$groupItemTarget = $itemTarget = $fileSource = $parent = 0;
1473
-
1474
-		$result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
1475
-		if(!empty($result)) {
1476
-			$parent = $result['parent'];
1477
-			$itemSource = $result['itemSource'];
1478
-			$fileSource = $result['fileSource'];
1479
-			$suggestedItemTarget = $result['suggestedItemTarget'];
1480
-			$suggestedFileTarget = $result['suggestedFileTarget'];
1481
-			$filePath = $result['filePath'];
1482
-		}
1483
-
1484
-		$isGroupShare = false;
1485
-		if ($shareType == self::SHARE_TYPE_GROUP) {
1486
-			$isGroupShare = true;
1487
-			if (isset($shareWith['users'])) {
1488
-				$users = $shareWith['users'];
1489
-			} else {
1490
-				$group = \OC::$server->getGroupManager()->get($shareWith['group']);
1491
-				if ($group) {
1492
-					$users = $group->searchUsers('', -1, 0);
1493
-					$userIds = [];
1494
-					foreach ($users as $user) {
1495
-						$userIds[] = $user->getUID();
1496
-					}
1497
-					$users = $userIds;
1498
-				} else {
1499
-					$users = [];
1500
-				}
1501
-			}
1502
-			// remove current user from list
1503
-			if (in_array(\OCP\User::getUser(), $users)) {
1504
-				unset($users[array_search(\OCP\User::getUser(), $users)]);
1505
-			}
1506
-			$groupItemTarget = Helper::generateTarget($itemType, $itemSource,
1507
-				$shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
1508
-			$groupFileTarget = Helper::generateTarget($itemType, $itemSource,
1509
-				$shareType, $shareWith['group'], $uidOwner, $filePath);
1510
-
1511
-			// add group share to table and remember the id as parent
1512
-			$queriesToExecute['groupShare'] = array(
1513
-				'itemType'			=> $itemType,
1514
-				'itemSource'		=> $itemSource,
1515
-				'itemTarget'		=> $groupItemTarget,
1516
-				'shareType'			=> $shareType,
1517
-				'shareWith'			=> $shareWith['group'],
1518
-				'uidOwner'			=> $uidOwner,
1519
-				'permissions'		=> $permissions,
1520
-				'shareTime'			=> time(),
1521
-				'fileSource'		=> $fileSource,
1522
-				'fileTarget'		=> $groupFileTarget,
1523
-				'token'				=> $token,
1524
-				'parent'			=> $parent,
1525
-				'expiration'		=> $expirationDate,
1526
-			);
1527
-
1528
-		} else {
1529
-			$users = array($shareWith);
1530
-			$itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1531
-				$suggestedItemTarget);
1532
-		}
1533
-
1534
-		$run = true;
1535
-		$error = '';
1536
-		$preHookData = array(
1537
-			'itemType' => $itemType,
1538
-			'itemSource' => $itemSource,
1539
-			'shareType' => $shareType,
1540
-			'uidOwner' => $uidOwner,
1541
-			'permissions' => $permissions,
1542
-			'fileSource' => $fileSource,
1543
-			'expiration' => $expirationDate,
1544
-			'token' => $token,
1545
-			'run' => &$run,
1546
-			'error' => &$error
1547
-		);
1548
-
1549
-		$preHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
1550
-		$preHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
1551
-
1552
-		\OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
1553
-
1554
-		if ($run === false) {
1555
-			throw new \Exception($error);
1556
-		}
1557
-
1558
-		foreach ($users as $user) {
1559
-			$sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
1560
-			$sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
1561
-
1562
-			$userShareType = ($isGroupShare) ? self::$shareTypeGroupUserUnique : $shareType;
1563
-
1564
-			if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
1565
-				$fileTarget = $sourceExists['file_target'];
1566
-				$itemTarget = $sourceExists['item_target'];
1567
-
1568
-				// for group shares we don't need a additional entry if the target is the same
1569
-				if($isGroupShare && $groupItemTarget === $itemTarget) {
1570
-					continue;
1571
-				}
1572
-
1573
-			} elseif(!$sourceExists && !$isGroupShare)  {
1574
-
1575
-				$itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
1576
-					$uidOwner, $suggestedItemTarget, $parent);
1577
-				if (isset($fileSource)) {
1578
-					if ($parentFolder) {
1579
-						if ($parentFolder === true) {
1580
-							$fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
1581
-								$uidOwner, $suggestedFileTarget, $parent);
1582
-							if ($fileTarget != $groupFileTarget) {
1583
-								$parentFolders[$user]['folder'] = $fileTarget;
1584
-							}
1585
-						} else if (isset($parentFolder[$user])) {
1586
-							$fileTarget = $parentFolder[$user]['folder'].$itemSource;
1587
-							$parent = $parentFolder[$user]['id'];
1588
-						}
1589
-					} else {
1590
-						$fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
1591
-							$user, $uidOwner, $suggestedFileTarget, $parent);
1592
-					}
1593
-				} else {
1594
-					$fileTarget = null;
1595
-				}
1596
-
1597
-			} else {
1598
-
1599
-				// group share which doesn't exists until now, check if we need a unique target for this user
1600
-
1601
-				$itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
1602
-					$uidOwner, $suggestedItemTarget, $parent);
1603
-
1604
-				// do we also need a file target
1605
-				if (isset($fileSource)) {
1606
-					$fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
1607
-						$uidOwner, $suggestedFileTarget, $parent);
1608
-				} else {
1609
-					$fileTarget = null;
1610
-				}
1611
-
1612
-				if (($itemTarget === $groupItemTarget) &&
1613
-					(!isset($fileSource) || $fileTarget === $groupFileTarget)) {
1614
-					continue;
1615
-				}
1616
-			}
1617
-
1618
-			$queriesToExecute[] = array(
1619
-				'itemType'			=> $itemType,
1620
-				'itemSource'		=> $itemSource,
1621
-				'itemTarget'		=> $itemTarget,
1622
-				'shareType'			=> $userShareType,
1623
-				'shareWith'			=> $user,
1624
-				'uidOwner'			=> $uidOwner,
1625
-				'permissions'		=> $permissions,
1626
-				'shareTime'			=> time(),
1627
-				'fileSource'		=> $fileSource,
1628
-				'fileTarget'		=> $fileTarget,
1629
-				'token'				=> $token,
1630
-				'parent'			=> $parent,
1631
-				'expiration'		=> $expirationDate,
1632
-			);
1633
-
1634
-		}
1635
-
1636
-		$id = false;
1637
-		if ($isGroupShare) {
1638
-			$id = self::insertShare($queriesToExecute['groupShare']);
1639
-			// Save this id, any extra rows for this group share will need to reference it
1640
-			$parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1641
-			unset($queriesToExecute['groupShare']);
1642
-		}
1643
-
1644
-		foreach ($queriesToExecute as $shareQuery) {
1645
-			$shareQuery['parent'] = $parent;
1646
-			$id = self::insertShare($shareQuery);
1647
-		}
1648
-
1649
-		$postHookData = array(
1650
-			'itemType' => $itemType,
1651
-			'itemSource' => $itemSource,
1652
-			'parent' => $parent,
1653
-			'shareType' => $shareType,
1654
-			'uidOwner' => $uidOwner,
1655
-			'permissions' => $permissions,
1656
-			'fileSource' => $fileSource,
1657
-			'id' => $parent,
1658
-			'token' => $token,
1659
-			'expirationDate' => $expirationDate,
1660
-		);
1661
-
1662
-		$postHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
1663
-		$postHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
1664
-		$postHookData['fileTarget'] = ($isGroupShare) ? $groupFileTarget : $fileTarget;
1665
-
1666
-		\OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
1667
-
1668
-
1669
-		return $id ? $id : false;
1670
-	}
1671
-
1672
-	/**
1673
-	 * @param string $itemType
1674
-	 * @param string $itemSource
1675
-	 * @param int $shareType
1676
-	 * @param string $shareWith
1677
-	 * @param string $uidOwner
1678
-	 * @param int $permissions
1679
-	 * @param string|null $itemSourceName
1680
-	 * @param null|\DateTime $expirationDate
1681
-	 */
1682
-	private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
1683
-		$backend = self::getBackend($itemType);
1684
-
1685
-		$l = \OC::$server->getL10N('lib');
1686
-		$result = array();
1687
-
1688
-		$column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
1689
-
1690
-		$checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
1691
-		if ($checkReshare) {
1692
-			// Check if attempting to share back to owner
1693
-			if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
1694
-				$message = 'Sharing %s failed, because the user %s is the original sharer';
1695
-				$message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
1696
-
1697
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
1698
-				throw new \Exception($message_t);
1699
-			}
1700
-		}
1701
-
1702
-		if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
1703
-			// Check if share permissions is granted
1704
-			if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1705
-				if (~(int)$checkReshare['permissions'] & $permissions) {
1706
-					$message = 'Sharing %s failed, because the permissions exceed permissions granted to %s';
1707
-					$message_t = $l->t('Sharing %s failed, because the permissions exceed permissions granted to %s', array($itemSourceName, $uidOwner));
1708
-
1709
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), \OCP\Util::DEBUG);
1710
-					throw new \Exception($message_t);
1711
-				} else {
1712
-					// TODO Don't check if inside folder
1713
-					$result['parent'] = $checkReshare['id'];
1714
-
1715
-					$result['expirationDate'] = $expirationDate;
1716
-					// $checkReshare['expiration'] could be null and then is always less than any value
1717
-					if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
1718
-						$result['expirationDate'] = $checkReshare['expiration'];
1719
-					}
1720
-
1721
-					// only suggest the same name as new target if it is a reshare of the
1722
-					// same file/folder and not the reshare of a child
1723
-					if ($checkReshare[$column] === $itemSource) {
1724
-						$result['filePath'] = $checkReshare['file_target'];
1725
-						$result['itemSource'] = $checkReshare['item_source'];
1726
-						$result['fileSource'] = $checkReshare['file_source'];
1727
-						$result['suggestedItemTarget'] = $checkReshare['item_target'];
1728
-						$result['suggestedFileTarget'] = $checkReshare['file_target'];
1729
-					} else {
1730
-						$result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
1731
-						$result['suggestedItemTarget'] = null;
1732
-						$result['suggestedFileTarget'] = null;
1733
-						$result['itemSource'] = $itemSource;
1734
-						$result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
1735
-					}
1736
-				}
1737
-			} else {
1738
-				$message = 'Sharing %s failed, because resharing is not allowed';
1739
-				$message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
1740
-
1741
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
1742
-				throw new \Exception($message_t);
1743
-			}
1744
-		} else {
1745
-			$result['parent'] = null;
1746
-			$result['suggestedItemTarget'] = null;
1747
-			$result['suggestedFileTarget'] = null;
1748
-			$result['itemSource'] = $itemSource;
1749
-			$result['expirationDate'] = $expirationDate;
1750
-			if (!$backend->isValidSource($itemSource, $uidOwner)) {
1751
-				$message = 'Sharing %s failed, because the sharing backend for '
1752
-					.'%s could not find its source';
1753
-				$message_t = $l->t('Sharing %s failed, because the sharing backend for %s could not find its source', array($itemSource, $itemType));
1754
-				\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), \OCP\Util::DEBUG);
1755
-				throw new \Exception($message_t);
1756
-			}
1757
-			if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1758
-				$result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
1759
-				if ($itemType == 'file' || $itemType == 'folder') {
1760
-					$result['fileSource'] = $itemSource;
1761
-				} else {
1762
-					$meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
1763
-					$result['fileSource'] = $meta['fileid'];
1764
-				}
1765
-				if ($result['fileSource'] == -1) {
1766
-					$message = 'Sharing %s failed, because the file could not be found in the file cache';
1767
-					$message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
1768
-
1769
-					\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
1770
-					throw new \Exception($message_t);
1771
-				}
1772
-			} else {
1773
-				$result['filePath'] = null;
1774
-				$result['fileSource'] = null;
1775
-			}
1776
-		}
1777
-
1778
-		return $result;
1779
-	}
1780
-
1781
-	/**
1782
-	 *
1783
-	 * @param array $shareData
1784
-	 * @return mixed false in case of a failure or the id of the new share
1785
-	 */
1786
-	private static function insertShare(array $shareData) {
1787
-
1788
-		$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
1789
-			.' `item_type`, `item_source`, `item_target`, `share_type`,'
1790
-			.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
1791
-			.' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
1792
-		$query->bindValue(1, $shareData['itemType']);
1793
-		$query->bindValue(2, $shareData['itemSource']);
1794
-		$query->bindValue(3, $shareData['itemTarget']);
1795
-		$query->bindValue(4, $shareData['shareType']);
1796
-		$query->bindValue(5, $shareData['shareWith']);
1797
-		$query->bindValue(6, $shareData['uidOwner']);
1798
-		$query->bindValue(7, $shareData['permissions']);
1799
-		$query->bindValue(8, $shareData['shareTime']);
1800
-		$query->bindValue(9, $shareData['fileSource']);
1801
-		$query->bindValue(10, $shareData['fileTarget']);
1802
-		$query->bindValue(11, $shareData['token']);
1803
-		$query->bindValue(12, $shareData['parent']);
1804
-		$query->bindValue(13, $shareData['expiration'], 'datetime');
1805
-		$result = $query->execute();
1806
-
1807
-		$id = false;
1808
-		if ($result) {
1809
-			$id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1810
-		}
1811
-
1812
-		return $id;
1813
-
1814
-	}
1815
-
1816
-	/**
1817
-	 * In case a password protected link is not yet authenticated this function will return false
1818
-	 *
1819
-	 * @param array $linkItem
1820
-	 * @return boolean
1821
-	 */
1822
-	public static function checkPasswordProtectedShare(array $linkItem) {
1823
-		if (!isset($linkItem['share_with'])) {
1824
-			return true;
1825
-		}
1826
-		if (!isset($linkItem['share_type'])) {
1827
-			return true;
1828
-		}
1829
-		if (!isset($linkItem['id'])) {
1830
-			return true;
1831
-		}
1832
-
1833
-		if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
1834
-			return true;
1835
-		}
1836
-
1837
-		if ( \OC::$server->getSession()->exists('public_link_authenticated')
1838
-			&& \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
1839
-			return true;
1840
-		}
1841
-
1842
-		return false;
1843
-	}
1844
-
1845
-	/**
1846
-	 * construct select statement
1847
-	 * @param int $format
1848
-	 * @param boolean $fileDependent ist it a file/folder share or a generla share
1849
-	 * @param string $uidOwner
1850
-	 * @return string select statement
1851
-	 */
1852
-	private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
1853
-		$select = '*';
1854
-		if ($format == self::FORMAT_STATUSES) {
1855
-			if ($fileDependent) {
1856
-				$select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
1857
-					. '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
1858
-					. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1859
-					. '`uid_initiator`';
1860
-			} else {
1861
-				$select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
1862
-			}
1863
-		} else {
1864
-			if (isset($uidOwner)) {
1865
-				if ($fileDependent) {
1866
-					$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
1867
-						. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
1868
-						. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
1869
-						. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1870
-				} else {
1871
-					$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
1872
-						. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
1873
-				}
1874
-			} else {
1875
-				if ($fileDependent) {
1876
-					if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
1877
-						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
1878
-							. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
1879
-							. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1880
-							. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
1881
-					} else {
1882
-						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
1883
-							. '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
1884
-							. '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
1885
-						    . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
1886
-							. '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1887
-					}
1888
-				}
1889
-			}
1890
-		}
1891
-		return $select;
1892
-	}
1893
-
1894
-
1895
-	/**
1896
-	 * transform db results
1897
-	 * @param array $row result
1898
-	 */
1899
-	private static function transformDBResults(&$row) {
1900
-		if (isset($row['id'])) {
1901
-			$row['id'] = (int) $row['id'];
1902
-		}
1903
-		if (isset($row['share_type'])) {
1904
-			$row['share_type'] = (int) $row['share_type'];
1905
-		}
1906
-		if (isset($row['parent'])) {
1907
-			$row['parent'] = (int) $row['parent'];
1908
-		}
1909
-		if (isset($row['file_parent'])) {
1910
-			$row['file_parent'] = (int) $row['file_parent'];
1911
-		}
1912
-		if (isset($row['file_source'])) {
1913
-			$row['file_source'] = (int) $row['file_source'];
1914
-		}
1915
-		if (isset($row['permissions'])) {
1916
-			$row['permissions'] = (int) $row['permissions'];
1917
-		}
1918
-		if (isset($row['storage'])) {
1919
-			$row['storage'] = (int) $row['storage'];
1920
-		}
1921
-		if (isset($row['stime'])) {
1922
-			$row['stime'] = (int) $row['stime'];
1923
-		}
1924
-		if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
1925
-			// discard expiration date for non-link shares, which might have been
1926
-			// set by ancient bugs
1927
-			$row['expiration'] = null;
1928
-		}
1929
-	}
1930
-
1931
-	/**
1932
-	 * format result
1933
-	 * @param array $items result
1934
-	 * @param string $column is it a file share or a general share ('file_target' or 'item_target')
1935
-	 * @param \OCP\Share_Backend $backend sharing backend
1936
-	 * @param int $format
1937
-	 * @param array $parameters additional format parameters
1938
-	 * @return array format result
1939
-	 */
1940
-	private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
1941
-		if ($format === self::FORMAT_NONE) {
1942
-			return $items;
1943
-		} else if ($format === self::FORMAT_STATUSES) {
1944
-			$statuses = array();
1945
-			foreach ($items as $item) {
1946
-				if ($item['share_type'] === self::SHARE_TYPE_LINK) {
1947
-					if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
1948
-						continue;
1949
-					}
1950
-					$statuses[$item[$column]]['link'] = true;
1951
-				} else if (!isset($statuses[$item[$column]])) {
1952
-					$statuses[$item[$column]]['link'] = false;
1953
-				}
1954
-				if (!empty($item['file_target'])) {
1955
-					$statuses[$item[$column]]['path'] = $item['path'];
1956
-				}
1957
-			}
1958
-			return $statuses;
1959
-		} else {
1960
-			return $backend->formatItems($items, $format, $parameters);
1961
-		}
1962
-	}
1963
-
1964
-	/**
1965
-	 * remove protocol from URL
1966
-	 *
1967
-	 * @param string $url
1968
-	 * @return string
1969
-	 */
1970
-	public static function removeProtocolFromUrl($url) {
1971
-		if (strpos($url, 'https://') === 0) {
1972
-			return substr($url, strlen('https://'));
1973
-		} else if (strpos($url, 'http://') === 0) {
1974
-			return substr($url, strlen('http://'));
1975
-		}
1976
-
1977
-		return $url;
1978
-	}
1979
-
1980
-	/**
1981
-	 * try http post first with https and then with http as a fallback
1982
-	 *
1983
-	 * @param string $remoteDomain
1984
-	 * @param string $urlSuffix
1985
-	 * @param array $fields post parameters
1986
-	 * @return array
1987
-	 */
1988
-	private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
1989
-		$protocol = 'https://';
1990
-		$result = [
1991
-			'success' => false,
1992
-			'result' => '',
1993
-		];
1994
-		$try = 0;
1995
-		$discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
1996
-		while ($result['success'] === false && $try < 2) {
1997
-			$federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
1998
-			$endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
1999
-			$result = \OC::$server->getHTTPHelper()->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, $fields);
2000
-			$try++;
2001
-			$protocol = 'http://';
2002
-		}
2003
-
2004
-		return $result;
2005
-	}
2006
-
2007
-	/**
2008
-	 * send server-to-server share to remote server
2009
-	 *
2010
-	 * @param string $token
2011
-	 * @param string $shareWith
2012
-	 * @param string $name
2013
-	 * @param int $remote_id
2014
-	 * @param string $owner
2015
-	 * @return bool
2016
-	 */
2017
-	private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
2018
-
2019
-		list($user, $remote) = Helper::splitUserRemote($shareWith);
2020
-
2021
-		if ($user && $remote) {
2022
-			$url = $remote;
2023
-
2024
-			$local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
2025
-
2026
-			$fields = array(
2027
-				'shareWith' => $user,
2028
-				'token' => $token,
2029
-				'name' => $name,
2030
-				'remoteId' => $remote_id,
2031
-				'owner' => $owner,
2032
-				'remote' => $local,
2033
-			);
2034
-
2035
-			$url = self::removeProtocolFromUrl($url);
2036
-			$result = self::tryHttpPostToShareEndpoint($url, '', $fields);
2037
-			$status = json_decode($result['result'], true);
2038
-
2039
-			if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
2040
-				\OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
2041
-				return true;
2042
-			}
2043
-
2044
-		}
2045
-
2046
-		return false;
2047
-	}
2048
-
2049
-	/**
2050
-	 * send server-to-server unshare to remote server
2051
-	 *
2052
-	 * @param string $remote url
2053
-	 * @param int $id share id
2054
-	 * @param string $token
2055
-	 * @return bool
2056
-	 */
2057
-	private static function sendRemoteUnshare($remote, $id, $token) {
2058
-		$url = rtrim($remote, '/');
2059
-		$fields = array('token' => $token, 'format' => 'json');
2060
-		$url = self::removeProtocolFromUrl($url);
2061
-		$result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
2062
-		$status = json_decode($result['result'], true);
2063
-
2064
-		return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
2065
-	}
2066
-
2067
-	/**
2068
-	 * check if user can only share with group members
2069
-	 * @return bool
2070
-	 */
2071
-	public static function shareWithGroupMembersOnly() {
2072
-		$value = \OC::$server->getConfig()->getAppValue('core', 'shareapi_only_share_with_group_members', 'no');
2073
-		return $value === 'yes';
2074
-	}
2075
-
2076
-	/**
2077
-	 * @return bool
2078
-	 */
2079
-	public static function isDefaultExpireDateEnabled() {
2080
-		$defaultExpireDateEnabled = \OC::$server->getConfig()->getAppValue('core', 'shareapi_default_expire_date', 'no');
2081
-		return $defaultExpireDateEnabled === 'yes';
2082
-	}
2083
-
2084
-	/**
2085
-	 * @return int
2086
-	 */
2087
-	public static function getExpireInterval() {
2088
-		return (int)\OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
2089
-	}
2090
-
2091
-	/**
2092
-	 * Checks whether the given path is reachable for the given owner
2093
-	 *
2094
-	 * @param string $path path relative to files
2095
-	 * @param string $ownerStorageId storage id of the owner
2096
-	 *
2097
-	 * @return boolean true if file is reachable, false otherwise
2098
-	 */
2099
-	private static function isFileReachable($path, $ownerStorageId) {
2100
-		// if outside the home storage, file is always considered reachable
2101
-		if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
2102
-			substr($ownerStorageId, 0, 13) === 'object::user:'
2103
-		)) {
2104
-			return true;
2105
-		}
2106
-
2107
-		// if inside the home storage, the file has to be under "/files/"
2108
-		$path = ltrim($path, '/');
2109
-		if (substr($path, 0, 6) === 'files/') {
2110
-			return true;
2111
-		}
2112
-
2113
-		return false;
2114
-	}
2115
-
2116
-	/**
2117
-	 * @param IConfig $config
2118
-	 * @return bool
2119
-	 */
2120
-	public static function enforcePassword(IConfig $config) {
2121
-		$enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
2122
-		return $enforcePassword === 'yes';
2123
-	}
2124
-
2125
-	/**
2126
-	 * @param string $password
2127
-	 * @throws \Exception
2128
-	 */
2129
-	private static function verifyPassword($password) {
2130
-
2131
-		$accepted = true;
2132
-		$message = '';
2133
-		\OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
2134
-			'password' => $password,
2135
-			'accepted' => &$accepted,
2136
-			'message' => &$message
2137
-		]);
2138
-
2139
-		if (!$accepted) {
2140
-			throw new \Exception($message);
2141
-		}
2142
-	}
731
+        $result = $query->execute(array($status, $itemType, $itemSource, $shareType, $recipient));
732
+
733
+        if($result === false) {
734
+            \OCP\Util::writeLog('OCP\Share', 'Couldn\'t set send mail status', \OCP\Util::ERROR);
735
+        }
736
+    }
737
+
738
+    /**
739
+     * validate expiration date if it meets all constraints
740
+     *
741
+     * @param string $expireDate well formatted date string, e.g. "DD-MM-YYYY"
742
+     * @param string $shareTime timestamp when the file was shared
743
+     * @param string $itemType
744
+     * @param string $itemSource
745
+     * @return \DateTime validated date
746
+     * @throws \Exception when the expire date is in the past or further in the future then the enforced date
747
+     */
748
+    private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
749
+        $l = \OC::$server->getL10N('lib');
750
+        $date = new \DateTime($expireDate);
751
+        $today = new \DateTime('now');
752
+
753
+        // if the user doesn't provide a share time we need to get it from the database
754
+        // fall-back mode to keep API stable, because the $shareTime parameter was added later
755
+        $defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
756
+        if ($defaultExpireDateEnforced && $shareTime === null) {
757
+            $items = self::getItemShared($itemType, $itemSource);
758
+            $firstItem = reset($items);
759
+            $shareTime = (int)$firstItem['stime'];
760
+        }
761
+
762
+        if ($defaultExpireDateEnforced) {
763
+            // initialize max date with share time
764
+            $maxDate = new \DateTime();
765
+            $maxDate->setTimestamp($shareTime);
766
+            $maxDays = \OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
767
+            $maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
768
+            if ($date > $maxDate) {
769
+                $warning = 'Cannot set expiration date. Shares cannot expire later than ' . $maxDays . ' after they have been shared';
770
+                $warning_t = $l->t('Cannot set expiration date. Shares cannot expire later than %s after they have been shared', array($maxDays));
771
+                \OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
772
+                throw new \Exception($warning_t);
773
+            }
774
+        }
775
+
776
+        if ($date < $today) {
777
+            $message = 'Cannot set expiration date. Expiration date is in the past';
778
+            $message_t = $l->t('Cannot set expiration date. Expiration date is in the past');
779
+            \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::WARN);
780
+            throw new \Exception($message_t);
781
+        }
782
+
783
+        return $date;
784
+    }
785
+
786
+    /**
787
+     * Checks whether a share has expired, calls unshareItem() if yes.
788
+     * @param array $item Share data (usually database row)
789
+     * @return boolean True if item was expired, false otherwise.
790
+     */
791
+    protected static function expireItem(array $item) {
792
+
793
+        $result = false;
794
+
795
+        // only use default expiration date for link shares
796
+        if ((int) $item['share_type'] === self::SHARE_TYPE_LINK) {
797
+
798
+            // calculate expiration date
799
+            if (!empty($item['expiration'])) {
800
+                $userDefinedExpire = new \DateTime($item['expiration']);
801
+                $expires = $userDefinedExpire->getTimestamp();
802
+            } else {
803
+                $expires = null;
804
+            }
805
+
806
+
807
+            // get default expiration settings
808
+            $defaultSettings = Helper::getDefaultExpireSetting();
809
+            $expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
810
+
811
+
812
+            if (is_int($expires)) {
813
+                $now = time();
814
+                if ($now > $expires) {
815
+                    self::unshareItem($item);
816
+                    $result = true;
817
+                }
818
+            }
819
+        }
820
+        return $result;
821
+    }
822
+
823
+    /**
824
+     * Unshares a share given a share data array
825
+     * @param array $item Share data (usually database row)
826
+     * @param int $newParent parent ID
827
+     * @return null
828
+     */
829
+    protected static function unshareItem(array $item, $newParent = null) {
830
+
831
+        $shareType = (int)$item['share_type'];
832
+        $shareWith = null;
833
+        if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
834
+            $shareWith = $item['share_with'];
835
+        }
836
+
837
+        // Pass all the vars we have for now, they may be useful
838
+        $hookParams = array(
839
+            'id'            => $item['id'],
840
+            'itemType'      => $item['item_type'],
841
+            'itemSource'    => $item['item_source'],
842
+            'shareType'     => $shareType,
843
+            'shareWith'     => $shareWith,
844
+            'itemParent'    => $item['parent'],
845
+            'uidOwner'      => $item['uid_owner'],
846
+        );
847
+        if($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
848
+            $hookParams['fileSource'] = $item['file_source'];
849
+            $hookParams['fileTarget'] = $item['file_target'];
850
+        }
851
+
852
+        \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams);
853
+        $deletedShares = Helper::delete($item['id'], false, null, $newParent);
854
+        $deletedShares[] = $hookParams;
855
+        $hookParams['deletedShares'] = $deletedShares;
856
+        \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
857
+        if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
858
+            list(, $remote) = Helper::splitUserRemote($item['share_with']);
859
+            self::sendRemoteUnshare($remote, $item['id'], $item['token']);
860
+        }
861
+    }
862
+
863
+    /**
864
+     * Get the backend class for the specified item type
865
+     * @param string $itemType
866
+     * @throws \Exception
867
+     * @return \OCP\Share_Backend
868
+     */
869
+    public static function getBackend($itemType) {
870
+        $l = \OC::$server->getL10N('lib');
871
+        if (isset(self::$backends[$itemType])) {
872
+            return self::$backends[$itemType];
873
+        } else if (isset(self::$backendTypes[$itemType]['class'])) {
874
+            $class = self::$backendTypes[$itemType]['class'];
875
+            if (class_exists($class)) {
876
+                self::$backends[$itemType] = new $class;
877
+                if (!(self::$backends[$itemType] instanceof \OCP\Share_Backend)) {
878
+                    $message = 'Sharing backend %s must implement the interface OCP\Share_Backend';
879
+                    $message_t = $l->t('Sharing backend %s must implement the interface OCP\Share_Backend', array($class));
880
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
881
+                    throw new \Exception($message_t);
882
+                }
883
+                return self::$backends[$itemType];
884
+            } else {
885
+                $message = 'Sharing backend %s not found';
886
+                $message_t = $l->t('Sharing backend %s not found', array($class));
887
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $class), \OCP\Util::ERROR);
888
+                throw new \Exception($message_t);
889
+            }
890
+        }
891
+        $message = 'Sharing backend for %s not found';
892
+        $message_t = $l->t('Sharing backend for %s not found', array($itemType));
893
+        \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemType), \OCP\Util::ERROR);
894
+        throw new \Exception($message_t);
895
+    }
896
+
897
+    /**
898
+     * Check if resharing is allowed
899
+     * @return boolean true if allowed or false
900
+     *
901
+     * Resharing is allowed by default if not configured
902
+     */
903
+    public static function isResharingAllowed() {
904
+        if (!isset(self::$isResharingAllowed)) {
905
+            if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_resharing', 'yes') == 'yes') {
906
+                self::$isResharingAllowed = true;
907
+            } else {
908
+                self::$isResharingAllowed = false;
909
+            }
910
+        }
911
+        return self::$isResharingAllowed;
912
+    }
913
+
914
+    /**
915
+     * Get a list of collection item types for the specified item type
916
+     * @param string $itemType
917
+     * @return array
918
+     */
919
+    private static function getCollectionItemTypes($itemType) {
920
+        $collectionTypes = array($itemType);
921
+        foreach (self::$backendTypes as $type => $backend) {
922
+            if (in_array($backend['collectionOf'], $collectionTypes)) {
923
+                $collectionTypes[] = $type;
924
+            }
925
+        }
926
+        // TODO Add option for collections to be collection of themselves, only 'folder' does it now...
927
+        if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
928
+            unset($collectionTypes[0]);
929
+        }
930
+        // Return array if collections were found or the item type is a
931
+        // collection itself - collections can be inside collections
932
+        if (count($collectionTypes) > 0) {
933
+            return $collectionTypes;
934
+        }
935
+        return false;
936
+    }
937
+
938
+    /**
939
+     * Get the owners of items shared with a user.
940
+     *
941
+     * @param string $user The user the items are shared with.
942
+     * @param string $type The type of the items shared with the user.
943
+     * @param boolean $includeCollections Include collection item types (optional)
944
+     * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
945
+     * @return array
946
+     */
947
+    public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
948
+        // First, we find out if $type is part of a collection (and if that collection is part of
949
+        // another one and so on).
950
+        $collectionTypes = array();
951
+        if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
952
+            $collectionTypes[] = $type;
953
+        }
954
+
955
+        // Of these collection types, along with our original $type, we make a
956
+        // list of the ones for which a sharing backend has been registered.
957
+        // FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
958
+        // with its $includeCollections parameter set to true. Unfortunately, this fails currently.
959
+        $allMaybeSharedItems = array();
960
+        foreach ($collectionTypes as $collectionType) {
961
+            if (isset(self::$backends[$collectionType])) {
962
+                $allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
963
+                    $collectionType,
964
+                    $user,
965
+                    self::FORMAT_NONE
966
+                );
967
+            }
968
+        }
969
+
970
+        $owners = array();
971
+        if ($includeOwner) {
972
+            $owners[] = $user;
973
+        }
974
+
975
+        // We take a look at all shared items of the given $type (or of the collections it is part of)
976
+        // and find out their owners. Then, we gather the tags for the original $type from all owners,
977
+        // and return them as elements of a list that look like "Tag (owner)".
978
+        foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
979
+            foreach ($maybeSharedItems as $sharedItem) {
980
+                if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
981
+                    $owners[] = $sharedItem['uid_owner'];
982
+                }
983
+            }
984
+        }
985
+
986
+        return $owners;
987
+    }
988
+
989
+    /**
990
+     * Get shared items from the database
991
+     * @param string $itemType
992
+     * @param string $item Item source or target (optional)
993
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
994
+     * @param string $shareWith User or group the item is being shared with
995
+     * @param string $uidOwner User that is the owner of shared items (optional)
996
+     * @param int $format Format to convert items to with formatItems() (optional)
997
+     * @param mixed $parameters to pass to formatItems() (optional)
998
+     * @param int $limit Number of items to return, -1 to return all matches (optional)
999
+     * @param boolean $includeCollections Include collection item types (optional)
1000
+     * @param boolean $itemShareWithBySource (optional)
1001
+     * @param boolean $checkExpireDate
1002
+     * @return array
1003
+     *
1004
+     * See public functions getItem(s)... for parameter usage
1005
+     *
1006
+     */
1007
+    public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
1008
+                                    $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
1009
+                                    $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
1010
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
1011
+            return array();
1012
+        }
1013
+        $backend = self::getBackend($itemType);
1014
+        $collectionTypes = false;
1015
+        // Get filesystem root to add it to the file target and remove from the
1016
+        // file source, match file_source with the file cache
1017
+        if ($itemType == 'file' || $itemType == 'folder') {
1018
+            if(!is_null($uidOwner)) {
1019
+                $root = \OC\Files\Filesystem::getRoot();
1020
+            } else {
1021
+                $root = '';
1022
+            }
1023
+            $where = 'INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` ';
1024
+            if (!isset($item)) {
1025
+                $where .= ' AND `file_target` IS NOT NULL ';
1026
+            }
1027
+            $where .= 'INNER JOIN `*PREFIX*storages` ON `numeric_id` = `*PREFIX*filecache`.`storage` ';
1028
+            $fileDependent = true;
1029
+            $queryArgs = array();
1030
+        } else {
1031
+            $fileDependent = false;
1032
+            $root = '';
1033
+            $collectionTypes = self::getCollectionItemTypes($itemType);
1034
+            if ($includeCollections && !isset($item) && $collectionTypes) {
1035
+                // If includeCollections is true, find collections of this item type, e.g. a music album contains songs
1036
+                if (!in_array($itemType, $collectionTypes)) {
1037
+                    $itemTypes = array_merge(array($itemType), $collectionTypes);
1038
+                } else {
1039
+                    $itemTypes = $collectionTypes;
1040
+                }
1041
+                $placeholders = join(',', array_fill(0, count($itemTypes), '?'));
1042
+                $where = ' WHERE `item_type` IN ('.$placeholders.'))';
1043
+                $queryArgs = $itemTypes;
1044
+            } else {
1045
+                $where = ' WHERE `item_type` = ?';
1046
+                $queryArgs = array($itemType);
1047
+            }
1048
+        }
1049
+        if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
1050
+            $where .= ' AND `share_type` != ?';
1051
+            $queryArgs[] = self::SHARE_TYPE_LINK;
1052
+        }
1053
+        if (isset($shareType)) {
1054
+            // Include all user and group items
1055
+            if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
1056
+                $where .= ' AND ((`share_type` in (?, ?) AND `share_with` = ?) ';
1057
+                $queryArgs[] = self::SHARE_TYPE_USER;
1058
+                $queryArgs[] = self::$shareTypeGroupUserUnique;
1059
+                $queryArgs[] = $shareWith;
1060
+
1061
+                $user = \OC::$server->getUserManager()->get($shareWith);
1062
+                $groups = [];
1063
+                if ($user) {
1064
+                    $groups = \OC::$server->getGroupManager()->getUserGroupIds($user);
1065
+                }
1066
+                if (!empty($groups)) {
1067
+                    $placeholders = join(',', array_fill(0, count($groups), '?'));
1068
+                    $where .= ' OR (`share_type` = ? AND `share_with` IN ('.$placeholders.')) ';
1069
+                    $queryArgs[] = self::SHARE_TYPE_GROUP;
1070
+                    $queryArgs = array_merge($queryArgs, $groups);
1071
+                }
1072
+                $where .= ')';
1073
+                // Don't include own group shares
1074
+                $where .= ' AND `uid_owner` != ?';
1075
+                $queryArgs[] = $shareWith;
1076
+            } else {
1077
+                $where .= ' AND `share_type` = ?';
1078
+                $queryArgs[] = $shareType;
1079
+                if (isset($shareWith)) {
1080
+                    $where .= ' AND `share_with` = ?';
1081
+                    $queryArgs[] = $shareWith;
1082
+                }
1083
+            }
1084
+        }
1085
+        if (isset($uidOwner)) {
1086
+            $where .= ' AND `uid_owner` = ?';
1087
+            $queryArgs[] = $uidOwner;
1088
+            if (!isset($shareType)) {
1089
+                // Prevent unique user targets for group shares from being selected
1090
+                $where .= ' AND `share_type` != ?';
1091
+                $queryArgs[] = self::$shareTypeGroupUserUnique;
1092
+            }
1093
+            if ($fileDependent) {
1094
+                $column = 'file_source';
1095
+            } else {
1096
+                $column = 'item_source';
1097
+            }
1098
+        } else {
1099
+            if ($fileDependent) {
1100
+                $column = 'file_target';
1101
+            } else {
1102
+                $column = 'item_target';
1103
+            }
1104
+        }
1105
+        if (isset($item)) {
1106
+            $collectionTypes = self::getCollectionItemTypes($itemType);
1107
+            if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1108
+                $where .= ' AND (';
1109
+            } else {
1110
+                $where .= ' AND';
1111
+            }
1112
+            // If looking for own shared items, check item_source else check item_target
1113
+            if (isset($uidOwner) || $itemShareWithBySource) {
1114
+                // If item type is a file, file source needs to be checked in case the item was converted
1115
+                if ($fileDependent) {
1116
+                    $where .= ' `file_source` = ?';
1117
+                    $column = 'file_source';
1118
+                } else {
1119
+                    $where .= ' `item_source` = ?';
1120
+                    $column = 'item_source';
1121
+                }
1122
+            } else {
1123
+                if ($fileDependent) {
1124
+                    $where .= ' `file_target` = ?';
1125
+                    $item = \OC\Files\Filesystem::normalizePath($item);
1126
+                } else {
1127
+                    $where .= ' `item_target` = ?';
1128
+                }
1129
+            }
1130
+            $queryArgs[] = $item;
1131
+            if ($includeCollections && $collectionTypes && !in_array('folder', $collectionTypes)) {
1132
+                $placeholders = join(',', array_fill(0, count($collectionTypes), '?'));
1133
+                $where .= ' OR `item_type` IN ('.$placeholders.'))';
1134
+                $queryArgs = array_merge($queryArgs, $collectionTypes);
1135
+            }
1136
+        }
1137
+
1138
+        if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
1139
+            // Make sure the unique user target is returned if it exists,
1140
+            // unique targets should follow the group share in the database
1141
+            // If the limit is not 1, the filtering can be done later
1142
+            $where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
1143
+        } else {
1144
+            $where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
1145
+        }
1146
+
1147
+        if ($limit != -1 && !$includeCollections) {
1148
+            // The limit must be at least 3, because filtering needs to be done
1149
+            if ($limit < 3) {
1150
+                $queryLimit = 3;
1151
+            } else {
1152
+                $queryLimit = $limit;
1153
+            }
1154
+        } else {
1155
+            $queryLimit = null;
1156
+        }
1157
+        $select = self::createSelectStatement($format, $fileDependent, $uidOwner);
1158
+        $root = strlen($root);
1159
+        $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
1160
+        $result = $query->execute($queryArgs);
1161
+        if ($result === false) {
1162
+            \OCP\Util::writeLog('OCP\Share',
1163
+                \OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
1164
+                \OCP\Util::ERROR);
1165
+        }
1166
+        $items = array();
1167
+        $targets = array();
1168
+        $switchedItems = array();
1169
+        $mounts = array();
1170
+        while ($row = $result->fetchRow()) {
1171
+            self::transformDBResults($row);
1172
+            // Filter out duplicate group shares for users with unique targets
1173
+            if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) {
1174
+                continue;
1175
+            }
1176
+            if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
1177
+                $row['share_type'] = self::SHARE_TYPE_GROUP;
1178
+                $row['unique_name'] = true; // remember that we use a unique name for this user
1179
+                $row['share_with'] = $items[$row['parent']]['share_with'];
1180
+                // if the group share was unshared from the user we keep the permission, otherwise
1181
+                // we take the permission from the parent because this is always the up-to-date
1182
+                // permission for the group share
1183
+                if ($row['permissions'] > 0) {
1184
+                    $row['permissions'] = $items[$row['parent']]['permissions'];
1185
+                }
1186
+                // Remove the parent group share
1187
+                unset($items[$row['parent']]);
1188
+                if ($row['permissions'] == 0) {
1189
+                    continue;
1190
+                }
1191
+            } else if (!isset($uidOwner)) {
1192
+                // Check if the same target already exists
1193
+                if (isset($targets[$row['id']])) {
1194
+                    // Check if the same owner shared with the user twice
1195
+                    // through a group and user share - this is allowed
1196
+                    $id = $targets[$row['id']];
1197
+                    if (isset($items[$id]) && $items[$id]['uid_owner'] == $row['uid_owner']) {
1198
+                        // Switch to group share type to ensure resharing conditions aren't bypassed
1199
+                        if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
1200
+                            $items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
1201
+                            $items[$id]['share_with'] = $row['share_with'];
1202
+                        }
1203
+                        // Switch ids if sharing permission is granted on only
1204
+                        // one share to ensure correct parent is used if resharing
1205
+                        if (~(int)$items[$id]['permissions'] & \OCP\Constants::PERMISSION_SHARE
1206
+                            && (int)$row['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1207
+                            $items[$row['id']] = $items[$id];
1208
+                            $switchedItems[$id] = $row['id'];
1209
+                            unset($items[$id]);
1210
+                            $id = $row['id'];
1211
+                        }
1212
+                        $items[$id]['permissions'] |= (int)$row['permissions'];
1213
+
1214
+                    }
1215
+                    continue;
1216
+                } elseif (!empty($row['parent'])) {
1217
+                    $targets[$row['parent']] = $row['id'];
1218
+                }
1219
+            }
1220
+            // Remove root from file source paths if retrieving own shared items
1221
+            if (isset($uidOwner) && isset($row['path'])) {
1222
+                if (isset($row['parent'])) {
1223
+                    $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
1224
+                    $parentResult = $query->execute(array($row['parent']));
1225
+                    if ($result === false) {
1226
+                        \OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
1227
+                            \OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
1228
+                            \OCP\Util::ERROR);
1229
+                    } else {
1230
+                        $parentRow = $parentResult->fetchRow();
1231
+                        $tmpPath = $parentRow['file_target'];
1232
+                        // find the right position where the row path continues from the target path
1233
+                        $pos = strrpos($row['path'], $parentRow['file_target']);
1234
+                        $subPath = substr($row['path'], $pos);
1235
+                        $splitPath = explode('/', $subPath);
1236
+                        foreach (array_slice($splitPath, 2) as $pathPart) {
1237
+                            $tmpPath = $tmpPath . '/' . $pathPart;
1238
+                        }
1239
+                        $row['path'] = $tmpPath;
1240
+                    }
1241
+                } else {
1242
+                    if (!isset($mounts[$row['storage']])) {
1243
+                        $mountPoints = \OC\Files\Filesystem::getMountByNumericId($row['storage']);
1244
+                        if (is_array($mountPoints) && !empty($mountPoints)) {
1245
+                            $mounts[$row['storage']] = current($mountPoints);
1246
+                        }
1247
+                    }
1248
+                    if (!empty($mounts[$row['storage']])) {
1249
+                        $path = $mounts[$row['storage']]->getMountPoint().$row['path'];
1250
+                        $relPath = substr($path, $root); // path relative to data/user
1251
+                        $row['path'] = rtrim($relPath, '/');
1252
+                    }
1253
+                }
1254
+            }
1255
+
1256
+            if($checkExpireDate) {
1257
+                if (self::expireItem($row)) {
1258
+                    continue;
1259
+                }
1260
+            }
1261
+            // Check if resharing is allowed, if not remove share permission
1262
+            if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
1263
+                $row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
1264
+            }
1265
+            // Add display names to result
1266
+            $row['share_with_displayname'] = $row['share_with'];
1267
+            if ( isset($row['share_with']) && $row['share_with'] != '' &&
1268
+                $row['share_type'] === self::SHARE_TYPE_USER) {
1269
+                $row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']);
1270
+            } else if(isset($row['share_with']) && $row['share_with'] != '' &&
1271
+                $row['share_type'] === self::SHARE_TYPE_REMOTE) {
1272
+                $addressBookEntries = \OC::$server->getContactsManager()->search($row['share_with'], ['CLOUD']);
1273
+                foreach ($addressBookEntries as $entry) {
1274
+                    foreach ($entry['CLOUD'] as $cloudID) {
1275
+                        if ($cloudID === $row['share_with']) {
1276
+                            $row['share_with_displayname'] = $entry['FN'];
1277
+                        }
1278
+                    }
1279
+                }
1280
+            }
1281
+            if ( isset($row['uid_owner']) && $row['uid_owner'] != '') {
1282
+                $row['displayname_owner'] = \OCP\User::getDisplayName($row['uid_owner']);
1283
+            }
1284
+
1285
+            if ($row['permissions'] > 0) {
1286
+                $items[$row['id']] = $row;
1287
+            }
1288
+
1289
+        }
1290
+
1291
+        // group items if we are looking for items shared with the current user
1292
+        if (isset($shareWith) && $shareWith === \OCP\User::getUser()) {
1293
+            $items = self::groupItems($items, $itemType);
1294
+        }
1295
+
1296
+        if (!empty($items)) {
1297
+            $collectionItems = array();
1298
+            foreach ($items as &$row) {
1299
+                // Return only the item instead of a 2-dimensional array
1300
+                if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
1301
+                    if ($format == self::FORMAT_NONE) {
1302
+                        return $row;
1303
+                    } else {
1304
+                        break;
1305
+                    }
1306
+                }
1307
+                // Check if this is a collection of the requested item type
1308
+                if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
1309
+                    if (($collectionBackend = self::getBackend($row['item_type']))
1310
+                        && $collectionBackend instanceof \OCP\Share_Backend_Collection) {
1311
+                        // Collections can be inside collections, check if the item is a collection
1312
+                        if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
1313
+                            $collectionItems[] = $row;
1314
+                        } else {
1315
+                            $collection = array();
1316
+                            $collection['item_type'] = $row['item_type'];
1317
+                            if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1318
+                                $collection['path'] = basename($row['path']);
1319
+                            }
1320
+                            $row['collection'] = $collection;
1321
+                            // Fetch all of the children sources
1322
+                            $children = $collectionBackend->getChildren($row[$column]);
1323
+                            foreach ($children as $child) {
1324
+                                $childItem = $row;
1325
+                                $childItem['item_type'] = $itemType;
1326
+                                if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
1327
+                                    $childItem['item_source'] = $child['source'];
1328
+                                    $childItem['item_target'] = $child['target'];
1329
+                                }
1330
+                                if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1331
+                                    if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
1332
+                                        $childItem['file_source'] = $child['source'];
1333
+                                    } else { // TODO is this really needed if we already know that we use the file backend?
1334
+                                        $meta = \OC\Files\Filesystem::getFileInfo($child['file_path']);
1335
+                                        $childItem['file_source'] = $meta['fileid'];
1336
+                                    }
1337
+                                    $childItem['file_target'] =
1338
+                                        \OC\Files\Filesystem::normalizePath($child['file_path']);
1339
+                                }
1340
+                                if (isset($item)) {
1341
+                                    if ($childItem[$column] == $item) {
1342
+                                        // Return only the item instead of a 2-dimensional array
1343
+                                        if ($limit == 1) {
1344
+                                            if ($format == self::FORMAT_NONE) {
1345
+                                                return $childItem;
1346
+                                            } else {
1347
+                                                // Unset the items array and break out of both loops
1348
+                                                $items = array();
1349
+                                                $items[] = $childItem;
1350
+                                                break 2;
1351
+                                            }
1352
+                                        } else {
1353
+                                            $collectionItems[] = $childItem;
1354
+                                        }
1355
+                                    }
1356
+                                } else {
1357
+                                    $collectionItems[] = $childItem;
1358
+                                }
1359
+                            }
1360
+                        }
1361
+                    }
1362
+                    // Remove collection item
1363
+                    $toRemove = $row['id'];
1364
+                    if (array_key_exists($toRemove, $switchedItems)) {
1365
+                        $toRemove = $switchedItems[$toRemove];
1366
+                    }
1367
+                    unset($items[$toRemove]);
1368
+                } elseif ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
1369
+                    // FIXME: Thats a dirty hack to improve file sharing performance,
1370
+                    // see github issue #10588 for more details
1371
+                    // Need to find a solution which works for all back-ends
1372
+                    $collectionBackend = self::getBackend($row['item_type']);
1373
+                    $sharedParents = $collectionBackend->getParents($row['item_source']);
1374
+                    foreach ($sharedParents as $parent) {
1375
+                        $collectionItems[] = $parent;
1376
+                    }
1377
+                }
1378
+            }
1379
+            if (!empty($collectionItems)) {
1380
+                $collectionItems = array_unique($collectionItems, SORT_REGULAR);
1381
+                $items = array_merge($items, $collectionItems);
1382
+            }
1383
+
1384
+            // filter out invalid items, these can appear when subshare entries exist
1385
+            // for a group in which the requested user isn't a member any more
1386
+            $items = array_filter($items, function($item) {
1387
+                return $item['share_type'] !== self::$shareTypeGroupUserUnique;
1388
+            });
1389
+
1390
+            return self::formatResult($items, $column, $backend, $format, $parameters);
1391
+        } elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
1392
+            // FIXME: Thats a dirty hack to improve file sharing performance,
1393
+            // see github issue #10588 for more details
1394
+            // Need to find a solution which works for all back-ends
1395
+            $collectionItems = array();
1396
+            $collectionBackend = self::getBackend('folder');
1397
+            $sharedParents = $collectionBackend->getParents($item, $shareWith, $uidOwner);
1398
+            foreach ($sharedParents as $parent) {
1399
+                $collectionItems[] = $parent;
1400
+            }
1401
+            if ($limit === 1) {
1402
+                return reset($collectionItems);
1403
+            }
1404
+            return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
1405
+        }
1406
+
1407
+        return array();
1408
+    }
1409
+
1410
+    /**
1411
+     * group items with link to the same source
1412
+     *
1413
+     * @param array $items
1414
+     * @param string $itemType
1415
+     * @return array of grouped items
1416
+     */
1417
+    protected static function groupItems($items, $itemType) {
1418
+
1419
+        $fileSharing = $itemType === 'file' || $itemType === 'folder';
1420
+
1421
+        $result = array();
1422
+
1423
+        foreach ($items as $item) {
1424
+            $grouped = false;
1425
+            foreach ($result as $key => $r) {
1426
+                // for file/folder shares we need to compare file_source, otherwise we compare item_source
1427
+                // only group shares if they already point to the same target, otherwise the file where shared
1428
+                // before grouping of shares was added. In this case we don't group them toi avoid confusions
1429
+                if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
1430
+                    (!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
1431
+                    // add the first item to the list of grouped shares
1432
+                    if (!isset($result[$key]['grouped'])) {
1433
+                        $result[$key]['grouped'][] = $result[$key];
1434
+                    }
1435
+                    $result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions'];
1436
+                    $result[$key]['grouped'][] = $item;
1437
+                    $grouped = true;
1438
+                    break;
1439
+                }
1440
+            }
1441
+
1442
+            if (!$grouped) {
1443
+                $result[] = $item;
1444
+            }
1445
+
1446
+        }
1447
+
1448
+        return $result;
1449
+    }
1450
+
1451
+    /**
1452
+     * Put shared item into the database
1453
+     * @param string $itemType Item type
1454
+     * @param string $itemSource Item source
1455
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
1456
+     * @param string $shareWith User or group the item is being shared with
1457
+     * @param string $uidOwner User that is the owner of shared item
1458
+     * @param int $permissions CRUDS permissions
1459
+     * @param boolean|array $parentFolder Parent folder target (optional)
1460
+     * @param string $token (optional)
1461
+     * @param string $itemSourceName name of the source item (optional)
1462
+     * @param \DateTime $expirationDate (optional)
1463
+     * @throws \Exception
1464
+     * @return mixed id of the new share or false
1465
+     */
1466
+    private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1467
+                                $permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
1468
+
1469
+        $queriesToExecute = array();
1470
+        $suggestedItemTarget = null;
1471
+        $groupFileTarget = $fileTarget = $suggestedFileTarget = $filePath = '';
1472
+        $groupItemTarget = $itemTarget = $fileSource = $parent = 0;
1473
+
1474
+        $result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate);
1475
+        if(!empty($result)) {
1476
+            $parent = $result['parent'];
1477
+            $itemSource = $result['itemSource'];
1478
+            $fileSource = $result['fileSource'];
1479
+            $suggestedItemTarget = $result['suggestedItemTarget'];
1480
+            $suggestedFileTarget = $result['suggestedFileTarget'];
1481
+            $filePath = $result['filePath'];
1482
+        }
1483
+
1484
+        $isGroupShare = false;
1485
+        if ($shareType == self::SHARE_TYPE_GROUP) {
1486
+            $isGroupShare = true;
1487
+            if (isset($shareWith['users'])) {
1488
+                $users = $shareWith['users'];
1489
+            } else {
1490
+                $group = \OC::$server->getGroupManager()->get($shareWith['group']);
1491
+                if ($group) {
1492
+                    $users = $group->searchUsers('', -1, 0);
1493
+                    $userIds = [];
1494
+                    foreach ($users as $user) {
1495
+                        $userIds[] = $user->getUID();
1496
+                    }
1497
+                    $users = $userIds;
1498
+                } else {
1499
+                    $users = [];
1500
+                }
1501
+            }
1502
+            // remove current user from list
1503
+            if (in_array(\OCP\User::getUser(), $users)) {
1504
+                unset($users[array_search(\OCP\User::getUser(), $users)]);
1505
+            }
1506
+            $groupItemTarget = Helper::generateTarget($itemType, $itemSource,
1507
+                $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
1508
+            $groupFileTarget = Helper::generateTarget($itemType, $itemSource,
1509
+                $shareType, $shareWith['group'], $uidOwner, $filePath);
1510
+
1511
+            // add group share to table and remember the id as parent
1512
+            $queriesToExecute['groupShare'] = array(
1513
+                'itemType'			=> $itemType,
1514
+                'itemSource'		=> $itemSource,
1515
+                'itemTarget'		=> $groupItemTarget,
1516
+                'shareType'			=> $shareType,
1517
+                'shareWith'			=> $shareWith['group'],
1518
+                'uidOwner'			=> $uidOwner,
1519
+                'permissions'		=> $permissions,
1520
+                'shareTime'			=> time(),
1521
+                'fileSource'		=> $fileSource,
1522
+                'fileTarget'		=> $groupFileTarget,
1523
+                'token'				=> $token,
1524
+                'parent'			=> $parent,
1525
+                'expiration'		=> $expirationDate,
1526
+            );
1527
+
1528
+        } else {
1529
+            $users = array($shareWith);
1530
+            $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
1531
+                $suggestedItemTarget);
1532
+        }
1533
+
1534
+        $run = true;
1535
+        $error = '';
1536
+        $preHookData = array(
1537
+            'itemType' => $itemType,
1538
+            'itemSource' => $itemSource,
1539
+            'shareType' => $shareType,
1540
+            'uidOwner' => $uidOwner,
1541
+            'permissions' => $permissions,
1542
+            'fileSource' => $fileSource,
1543
+            'expiration' => $expirationDate,
1544
+            'token' => $token,
1545
+            'run' => &$run,
1546
+            'error' => &$error
1547
+        );
1548
+
1549
+        $preHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
1550
+        $preHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
1551
+
1552
+        \OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
1553
+
1554
+        if ($run === false) {
1555
+            throw new \Exception($error);
1556
+        }
1557
+
1558
+        foreach ($users as $user) {
1559
+            $sourceId = ($itemType === 'file' || $itemType === 'folder') ? $fileSource : $itemSource;
1560
+            $sourceExists = self::getItemSharedWithBySource($itemType, $sourceId, self::FORMAT_NONE, null, true, $user);
1561
+
1562
+            $userShareType = ($isGroupShare) ? self::$shareTypeGroupUserUnique : $shareType;
1563
+
1564
+            if ($sourceExists && $sourceExists['item_source'] === $itemSource) {
1565
+                $fileTarget = $sourceExists['file_target'];
1566
+                $itemTarget = $sourceExists['item_target'];
1567
+
1568
+                // for group shares we don't need a additional entry if the target is the same
1569
+                if($isGroupShare && $groupItemTarget === $itemTarget) {
1570
+                    continue;
1571
+                }
1572
+
1573
+            } elseif(!$sourceExists && !$isGroupShare)  {
1574
+
1575
+                $itemTarget = Helper::generateTarget($itemType, $itemSource, $userShareType, $user,
1576
+                    $uidOwner, $suggestedItemTarget, $parent);
1577
+                if (isset($fileSource)) {
1578
+                    if ($parentFolder) {
1579
+                        if ($parentFolder === true) {
1580
+                            $fileTarget = Helper::generateTarget('file', $filePath, $userShareType, $user,
1581
+                                $uidOwner, $suggestedFileTarget, $parent);
1582
+                            if ($fileTarget != $groupFileTarget) {
1583
+                                $parentFolders[$user]['folder'] = $fileTarget;
1584
+                            }
1585
+                        } else if (isset($parentFolder[$user])) {
1586
+                            $fileTarget = $parentFolder[$user]['folder'].$itemSource;
1587
+                            $parent = $parentFolder[$user]['id'];
1588
+                        }
1589
+                    } else {
1590
+                        $fileTarget = Helper::generateTarget('file', $filePath, $userShareType,
1591
+                            $user, $uidOwner, $suggestedFileTarget, $parent);
1592
+                    }
1593
+                } else {
1594
+                    $fileTarget = null;
1595
+                }
1596
+
1597
+            } else {
1598
+
1599
+                // group share which doesn't exists until now, check if we need a unique target for this user
1600
+
1601
+                $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user,
1602
+                    $uidOwner, $suggestedItemTarget, $parent);
1603
+
1604
+                // do we also need a file target
1605
+                if (isset($fileSource)) {
1606
+                    $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
1607
+                        $uidOwner, $suggestedFileTarget, $parent);
1608
+                } else {
1609
+                    $fileTarget = null;
1610
+                }
1611
+
1612
+                if (($itemTarget === $groupItemTarget) &&
1613
+                    (!isset($fileSource) || $fileTarget === $groupFileTarget)) {
1614
+                    continue;
1615
+                }
1616
+            }
1617
+
1618
+            $queriesToExecute[] = array(
1619
+                'itemType'			=> $itemType,
1620
+                'itemSource'		=> $itemSource,
1621
+                'itemTarget'		=> $itemTarget,
1622
+                'shareType'			=> $userShareType,
1623
+                'shareWith'			=> $user,
1624
+                'uidOwner'			=> $uidOwner,
1625
+                'permissions'		=> $permissions,
1626
+                'shareTime'			=> time(),
1627
+                'fileSource'		=> $fileSource,
1628
+                'fileTarget'		=> $fileTarget,
1629
+                'token'				=> $token,
1630
+                'parent'			=> $parent,
1631
+                'expiration'		=> $expirationDate,
1632
+            );
1633
+
1634
+        }
1635
+
1636
+        $id = false;
1637
+        if ($isGroupShare) {
1638
+            $id = self::insertShare($queriesToExecute['groupShare']);
1639
+            // Save this id, any extra rows for this group share will need to reference it
1640
+            $parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1641
+            unset($queriesToExecute['groupShare']);
1642
+        }
1643
+
1644
+        foreach ($queriesToExecute as $shareQuery) {
1645
+            $shareQuery['parent'] = $parent;
1646
+            $id = self::insertShare($shareQuery);
1647
+        }
1648
+
1649
+        $postHookData = array(
1650
+            'itemType' => $itemType,
1651
+            'itemSource' => $itemSource,
1652
+            'parent' => $parent,
1653
+            'shareType' => $shareType,
1654
+            'uidOwner' => $uidOwner,
1655
+            'permissions' => $permissions,
1656
+            'fileSource' => $fileSource,
1657
+            'id' => $parent,
1658
+            'token' => $token,
1659
+            'expirationDate' => $expirationDate,
1660
+        );
1661
+
1662
+        $postHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith;
1663
+        $postHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget;
1664
+        $postHookData['fileTarget'] = ($isGroupShare) ? $groupFileTarget : $fileTarget;
1665
+
1666
+        \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
1667
+
1668
+
1669
+        return $id ? $id : false;
1670
+    }
1671
+
1672
+    /**
1673
+     * @param string $itemType
1674
+     * @param string $itemSource
1675
+     * @param int $shareType
1676
+     * @param string $shareWith
1677
+     * @param string $uidOwner
1678
+     * @param int $permissions
1679
+     * @param string|null $itemSourceName
1680
+     * @param null|\DateTime $expirationDate
1681
+     */
1682
+    private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
1683
+        $backend = self::getBackend($itemType);
1684
+
1685
+        $l = \OC::$server->getL10N('lib');
1686
+        $result = array();
1687
+
1688
+        $column = ($itemType === 'file' || $itemType === 'folder') ? 'file_source' : 'item_source';
1689
+
1690
+        $checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true);
1691
+        if ($checkReshare) {
1692
+            // Check if attempting to share back to owner
1693
+            if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
1694
+                $message = 'Sharing %s failed, because the user %s is the original sharer';
1695
+                $message_t = $l->t('Sharing failed, because the user %s is the original sharer', [$shareWith]);
1696
+
1697
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
1698
+                throw new \Exception($message_t);
1699
+            }
1700
+        }
1701
+
1702
+        if ($checkReshare && $checkReshare['uid_owner'] !== \OC_User::getUser()) {
1703
+            // Check if share permissions is granted
1704
+            if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\Constants::PERMISSION_SHARE) {
1705
+                if (~(int)$checkReshare['permissions'] & $permissions) {
1706
+                    $message = 'Sharing %s failed, because the permissions exceed permissions granted to %s';
1707
+                    $message_t = $l->t('Sharing %s failed, because the permissions exceed permissions granted to %s', array($itemSourceName, $uidOwner));
1708
+
1709
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $uidOwner), \OCP\Util::DEBUG);
1710
+                    throw new \Exception($message_t);
1711
+                } else {
1712
+                    // TODO Don't check if inside folder
1713
+                    $result['parent'] = $checkReshare['id'];
1714
+
1715
+                    $result['expirationDate'] = $expirationDate;
1716
+                    // $checkReshare['expiration'] could be null and then is always less than any value
1717
+                    if(isset($checkReshare['expiration']) && $checkReshare['expiration'] < $expirationDate) {
1718
+                        $result['expirationDate'] = $checkReshare['expiration'];
1719
+                    }
1720
+
1721
+                    // only suggest the same name as new target if it is a reshare of the
1722
+                    // same file/folder and not the reshare of a child
1723
+                    if ($checkReshare[$column] === $itemSource) {
1724
+                        $result['filePath'] = $checkReshare['file_target'];
1725
+                        $result['itemSource'] = $checkReshare['item_source'];
1726
+                        $result['fileSource'] = $checkReshare['file_source'];
1727
+                        $result['suggestedItemTarget'] = $checkReshare['item_target'];
1728
+                        $result['suggestedFileTarget'] = $checkReshare['file_target'];
1729
+                    } else {
1730
+                        $result['filePath'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $backend->getFilePath($itemSource, $uidOwner) : null;
1731
+                        $result['suggestedItemTarget'] = null;
1732
+                        $result['suggestedFileTarget'] = null;
1733
+                        $result['itemSource'] = $itemSource;
1734
+                        $result['fileSource'] = ($backend instanceof \OCP\Share_Backend_File_Dependent) ? $itemSource : null;
1735
+                    }
1736
+                }
1737
+            } else {
1738
+                $message = 'Sharing %s failed, because resharing is not allowed';
1739
+                $message_t = $l->t('Sharing %s failed, because resharing is not allowed', array($itemSourceName));
1740
+
1741
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName), \OCP\Util::DEBUG);
1742
+                throw new \Exception($message_t);
1743
+            }
1744
+        } else {
1745
+            $result['parent'] = null;
1746
+            $result['suggestedItemTarget'] = null;
1747
+            $result['suggestedFileTarget'] = null;
1748
+            $result['itemSource'] = $itemSource;
1749
+            $result['expirationDate'] = $expirationDate;
1750
+            if (!$backend->isValidSource($itemSource, $uidOwner)) {
1751
+                $message = 'Sharing %s failed, because the sharing backend for '
1752
+                    .'%s could not find its source';
1753
+                $message_t = $l->t('Sharing %s failed, because the sharing backend for %s could not find its source', array($itemSource, $itemType));
1754
+                \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource, $itemType), \OCP\Util::DEBUG);
1755
+                throw new \Exception($message_t);
1756
+            }
1757
+            if ($backend instanceof \OCP\Share_Backend_File_Dependent) {
1758
+                $result['filePath'] = $backend->getFilePath($itemSource, $uidOwner);
1759
+                if ($itemType == 'file' || $itemType == 'folder') {
1760
+                    $result['fileSource'] = $itemSource;
1761
+                } else {
1762
+                    $meta = \OC\Files\Filesystem::getFileInfo($result['filePath']);
1763
+                    $result['fileSource'] = $meta['fileid'];
1764
+                }
1765
+                if ($result['fileSource'] == -1) {
1766
+                    $message = 'Sharing %s failed, because the file could not be found in the file cache';
1767
+                    $message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource));
1768
+
1769
+                    \OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSource), \OCP\Util::DEBUG);
1770
+                    throw new \Exception($message_t);
1771
+                }
1772
+            } else {
1773
+                $result['filePath'] = null;
1774
+                $result['fileSource'] = null;
1775
+            }
1776
+        }
1777
+
1778
+        return $result;
1779
+    }
1780
+
1781
+    /**
1782
+     *
1783
+     * @param array $shareData
1784
+     * @return mixed false in case of a failure or the id of the new share
1785
+     */
1786
+    private static function insertShare(array $shareData) {
1787
+
1788
+        $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
1789
+            .' `item_type`, `item_source`, `item_target`, `share_type`,'
1790
+            .' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
1791
+            .' `file_target`, `token`, `parent`, `expiration`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)');
1792
+        $query->bindValue(1, $shareData['itemType']);
1793
+        $query->bindValue(2, $shareData['itemSource']);
1794
+        $query->bindValue(3, $shareData['itemTarget']);
1795
+        $query->bindValue(4, $shareData['shareType']);
1796
+        $query->bindValue(5, $shareData['shareWith']);
1797
+        $query->bindValue(6, $shareData['uidOwner']);
1798
+        $query->bindValue(7, $shareData['permissions']);
1799
+        $query->bindValue(8, $shareData['shareTime']);
1800
+        $query->bindValue(9, $shareData['fileSource']);
1801
+        $query->bindValue(10, $shareData['fileTarget']);
1802
+        $query->bindValue(11, $shareData['token']);
1803
+        $query->bindValue(12, $shareData['parent']);
1804
+        $query->bindValue(13, $shareData['expiration'], 'datetime');
1805
+        $result = $query->execute();
1806
+
1807
+        $id = false;
1808
+        if ($result) {
1809
+            $id =  \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
1810
+        }
1811
+
1812
+        return $id;
1813
+
1814
+    }
1815
+
1816
+    /**
1817
+     * In case a password protected link is not yet authenticated this function will return false
1818
+     *
1819
+     * @param array $linkItem
1820
+     * @return boolean
1821
+     */
1822
+    public static function checkPasswordProtectedShare(array $linkItem) {
1823
+        if (!isset($linkItem['share_with'])) {
1824
+            return true;
1825
+        }
1826
+        if (!isset($linkItem['share_type'])) {
1827
+            return true;
1828
+        }
1829
+        if (!isset($linkItem['id'])) {
1830
+            return true;
1831
+        }
1832
+
1833
+        if ($linkItem['share_type'] != \OCP\Share::SHARE_TYPE_LINK) {
1834
+            return true;
1835
+        }
1836
+
1837
+        if ( \OC::$server->getSession()->exists('public_link_authenticated')
1838
+            && \OC::$server->getSession()->get('public_link_authenticated') === (string)$linkItem['id'] ) {
1839
+            return true;
1840
+        }
1841
+
1842
+        return false;
1843
+    }
1844
+
1845
+    /**
1846
+     * construct select statement
1847
+     * @param int $format
1848
+     * @param boolean $fileDependent ist it a file/folder share or a generla share
1849
+     * @param string $uidOwner
1850
+     * @return string select statement
1851
+     */
1852
+    private static function createSelectStatement($format, $fileDependent, $uidOwner = null) {
1853
+        $select = '*';
1854
+        if ($format == self::FORMAT_STATUSES) {
1855
+            if ($fileDependent) {
1856
+                $select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, '
1857
+                    . '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, '
1858
+                    . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1859
+                    . '`uid_initiator`';
1860
+            } else {
1861
+                $select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`';
1862
+            }
1863
+        } else {
1864
+            if (isset($uidOwner)) {
1865
+                if ($fileDependent) {
1866
+                    $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
1867
+                        . ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
1868
+                        . ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, '
1869
+                        . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1870
+                } else {
1871
+                    $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
1872
+                        . ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
1873
+                }
1874
+            } else {
1875
+                if ($fileDependent) {
1876
+                    if ($format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_GET_FOLDER_CONTENTS || $format == \OCA\Files_Sharing\ShareBackend\File::FORMAT_FILE_APP_ROOT) {
1877
+                        $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
1878
+                            . '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
1879
+                            . '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
1880
+                            . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
1881
+                    } else {
1882
+                        $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,'
1883
+                            . '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,'
1884
+                            . '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,'
1885
+                            . '`stime`, `expiration`, `token`, `storage`, `mail_send`,'
1886
+                            . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`';
1887
+                    }
1888
+                }
1889
+            }
1890
+        }
1891
+        return $select;
1892
+    }
1893
+
1894
+
1895
+    /**
1896
+     * transform db results
1897
+     * @param array $row result
1898
+     */
1899
+    private static function transformDBResults(&$row) {
1900
+        if (isset($row['id'])) {
1901
+            $row['id'] = (int) $row['id'];
1902
+        }
1903
+        if (isset($row['share_type'])) {
1904
+            $row['share_type'] = (int) $row['share_type'];
1905
+        }
1906
+        if (isset($row['parent'])) {
1907
+            $row['parent'] = (int) $row['parent'];
1908
+        }
1909
+        if (isset($row['file_parent'])) {
1910
+            $row['file_parent'] = (int) $row['file_parent'];
1911
+        }
1912
+        if (isset($row['file_source'])) {
1913
+            $row['file_source'] = (int) $row['file_source'];
1914
+        }
1915
+        if (isset($row['permissions'])) {
1916
+            $row['permissions'] = (int) $row['permissions'];
1917
+        }
1918
+        if (isset($row['storage'])) {
1919
+            $row['storage'] = (int) $row['storage'];
1920
+        }
1921
+        if (isset($row['stime'])) {
1922
+            $row['stime'] = (int) $row['stime'];
1923
+        }
1924
+        if (isset($row['expiration']) && $row['share_type'] !== self::SHARE_TYPE_LINK) {
1925
+            // discard expiration date for non-link shares, which might have been
1926
+            // set by ancient bugs
1927
+            $row['expiration'] = null;
1928
+        }
1929
+    }
1930
+
1931
+    /**
1932
+     * format result
1933
+     * @param array $items result
1934
+     * @param string $column is it a file share or a general share ('file_target' or 'item_target')
1935
+     * @param \OCP\Share_Backend $backend sharing backend
1936
+     * @param int $format
1937
+     * @param array $parameters additional format parameters
1938
+     * @return array format result
1939
+     */
1940
+    private static function formatResult($items, $column, $backend, $format = self::FORMAT_NONE , $parameters = null) {
1941
+        if ($format === self::FORMAT_NONE) {
1942
+            return $items;
1943
+        } else if ($format === self::FORMAT_STATUSES) {
1944
+            $statuses = array();
1945
+            foreach ($items as $item) {
1946
+                if ($item['share_type'] === self::SHARE_TYPE_LINK) {
1947
+                    if ($item['uid_initiator'] !== \OC::$server->getUserSession()->getUser()->getUID()) {
1948
+                        continue;
1949
+                    }
1950
+                    $statuses[$item[$column]]['link'] = true;
1951
+                } else if (!isset($statuses[$item[$column]])) {
1952
+                    $statuses[$item[$column]]['link'] = false;
1953
+                }
1954
+                if (!empty($item['file_target'])) {
1955
+                    $statuses[$item[$column]]['path'] = $item['path'];
1956
+                }
1957
+            }
1958
+            return $statuses;
1959
+        } else {
1960
+            return $backend->formatItems($items, $format, $parameters);
1961
+        }
1962
+    }
1963
+
1964
+    /**
1965
+     * remove protocol from URL
1966
+     *
1967
+     * @param string $url
1968
+     * @return string
1969
+     */
1970
+    public static function removeProtocolFromUrl($url) {
1971
+        if (strpos($url, 'https://') === 0) {
1972
+            return substr($url, strlen('https://'));
1973
+        } else if (strpos($url, 'http://') === 0) {
1974
+            return substr($url, strlen('http://'));
1975
+        }
1976
+
1977
+        return $url;
1978
+    }
1979
+
1980
+    /**
1981
+     * try http post first with https and then with http as a fallback
1982
+     *
1983
+     * @param string $remoteDomain
1984
+     * @param string $urlSuffix
1985
+     * @param array $fields post parameters
1986
+     * @return array
1987
+     */
1988
+    private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
1989
+        $protocol = 'https://';
1990
+        $result = [
1991
+            'success' => false,
1992
+            'result' => '',
1993
+        ];
1994
+        $try = 0;
1995
+        $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
1996
+        while ($result['success'] === false && $try < 2) {
1997
+            $federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
1998
+            $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
1999
+            $result = \OC::$server->getHTTPHelper()->post($protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT, $fields);
2000
+            $try++;
2001
+            $protocol = 'http://';
2002
+        }
2003
+
2004
+        return $result;
2005
+    }
2006
+
2007
+    /**
2008
+     * send server-to-server share to remote server
2009
+     *
2010
+     * @param string $token
2011
+     * @param string $shareWith
2012
+     * @param string $name
2013
+     * @param int $remote_id
2014
+     * @param string $owner
2015
+     * @return bool
2016
+     */
2017
+    private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
2018
+
2019
+        list($user, $remote) = Helper::splitUserRemote($shareWith);
2020
+
2021
+        if ($user && $remote) {
2022
+            $url = $remote;
2023
+
2024
+            $local = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
2025
+
2026
+            $fields = array(
2027
+                'shareWith' => $user,
2028
+                'token' => $token,
2029
+                'name' => $name,
2030
+                'remoteId' => $remote_id,
2031
+                'owner' => $owner,
2032
+                'remote' => $local,
2033
+            );
2034
+
2035
+            $url = self::removeProtocolFromUrl($url);
2036
+            $result = self::tryHttpPostToShareEndpoint($url, '', $fields);
2037
+            $status = json_decode($result['result'], true);
2038
+
2039
+            if ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)) {
2040
+                \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $remote]);
2041
+                return true;
2042
+            }
2043
+
2044
+        }
2045
+
2046
+        return false;
2047
+    }
2048
+
2049
+    /**
2050
+     * send server-to-server unshare to remote server
2051
+     *
2052
+     * @param string $remote url
2053
+     * @param int $id share id
2054
+     * @param string $token
2055
+     * @return bool
2056
+     */
2057
+    private static function sendRemoteUnshare($remote, $id, $token) {
2058
+        $url = rtrim($remote, '/');
2059
+        $fields = array('token' => $token, 'format' => 'json');
2060
+        $url = self::removeProtocolFromUrl($url);
2061
+        $result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
2062
+        $status = json_decode($result['result'], true);
2063
+
2064
+        return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
2065
+    }
2066
+
2067
+    /**
2068
+     * check if user can only share with group members
2069
+     * @return bool
2070
+     */
2071
+    public static function shareWithGroupMembersOnly() {
2072
+        $value = \OC::$server->getConfig()->getAppValue('core', 'shareapi_only_share_with_group_members', 'no');
2073
+        return $value === 'yes';
2074
+    }
2075
+
2076
+    /**
2077
+     * @return bool
2078
+     */
2079
+    public static function isDefaultExpireDateEnabled() {
2080
+        $defaultExpireDateEnabled = \OC::$server->getConfig()->getAppValue('core', 'shareapi_default_expire_date', 'no');
2081
+        return $defaultExpireDateEnabled === 'yes';
2082
+    }
2083
+
2084
+    /**
2085
+     * @return int
2086
+     */
2087
+    public static function getExpireInterval() {
2088
+        return (int)\OC::$server->getConfig()->getAppValue('core', 'shareapi_expire_after_n_days', '7');
2089
+    }
2090
+
2091
+    /**
2092
+     * Checks whether the given path is reachable for the given owner
2093
+     *
2094
+     * @param string $path path relative to files
2095
+     * @param string $ownerStorageId storage id of the owner
2096
+     *
2097
+     * @return boolean true if file is reachable, false otherwise
2098
+     */
2099
+    private static function isFileReachable($path, $ownerStorageId) {
2100
+        // if outside the home storage, file is always considered reachable
2101
+        if (!(substr($ownerStorageId, 0, 6) === 'home::' ||
2102
+            substr($ownerStorageId, 0, 13) === 'object::user:'
2103
+        )) {
2104
+            return true;
2105
+        }
2106
+
2107
+        // if inside the home storage, the file has to be under "/files/"
2108
+        $path = ltrim($path, '/');
2109
+        if (substr($path, 0, 6) === 'files/') {
2110
+            return true;
2111
+        }
2112
+
2113
+        return false;
2114
+    }
2115
+
2116
+    /**
2117
+     * @param IConfig $config
2118
+     * @return bool
2119
+     */
2120
+    public static function enforcePassword(IConfig $config) {
2121
+        $enforcePassword = $config->getAppValue('core', 'shareapi_enforce_links_password', 'no');
2122
+        return $enforcePassword === 'yes';
2123
+    }
2124
+
2125
+    /**
2126
+     * @param string $password
2127
+     * @throws \Exception
2128
+     */
2129
+    private static function verifyPassword($password) {
2130
+
2131
+        $accepted = true;
2132
+        $message = '';
2133
+        \OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
2134
+            'password' => $password,
2135
+            'accepted' => &$accepted,
2136
+            'message' => &$message
2137
+        ]);
2138
+
2139
+        if (!$accepted) {
2140
+            throw new \Exception($message);
2141
+        }
2142
+    }
2143 2143
 }
Please login to merge, or discard this patch.
lib/private/Share/Helper.php 2 patches
Indentation   +232 added lines, -232 removed lines patch added patch discarded remove patch
@@ -33,263 +33,263 @@
 block discarded – undo
33 33
 
34 34
 class Helper extends \OC\Share\Constants {
35 35
 
36
-	/**
37
-	 * Generate a unique target for the item
38
-	 * @param string $itemType
39
-	 * @param string $itemSource
40
-	 * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
41
-	 * @param string $shareWith User or group the item is being shared with
42
-	 * @param string $uidOwner User that is the owner of shared item
43
-	 * @param string $suggestedTarget The suggested target originating from a reshare (optional)
44
-	 * @param int $groupParent The id of the parent group share (optional)
45
-	 * @throws \Exception
46
-	 * @return string Item target
47
-	 */
48
-	public static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedTarget = null, $groupParent = null) {
49
-		// FIXME: $uidOwner and $groupParent seems to be unused
50
-		$backend = \OC\Share\Share::getBackend($itemType);
51
-		if ($shareType === self::SHARE_TYPE_LINK || $shareType === self::SHARE_TYPE_REMOTE) {
52
-			if (isset($suggestedTarget)) {
53
-				return $suggestedTarget;
54
-			}
55
-			return $backend->generateTarget($itemSource, false);
56
-		} else {
57
-			if ($shareType == self::SHARE_TYPE_USER) {
58
-				// Share with is a user, so set share type to user and groups
59
-				$shareType = self::$shareTypeUserAndGroups;
60
-			}
36
+    /**
37
+     * Generate a unique target for the item
38
+     * @param string $itemType
39
+     * @param string $itemSource
40
+     * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
41
+     * @param string $shareWith User or group the item is being shared with
42
+     * @param string $uidOwner User that is the owner of shared item
43
+     * @param string $suggestedTarget The suggested target originating from a reshare (optional)
44
+     * @param int $groupParent The id of the parent group share (optional)
45
+     * @throws \Exception
46
+     * @return string Item target
47
+     */
48
+    public static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedTarget = null, $groupParent = null) {
49
+        // FIXME: $uidOwner and $groupParent seems to be unused
50
+        $backend = \OC\Share\Share::getBackend($itemType);
51
+        if ($shareType === self::SHARE_TYPE_LINK || $shareType === self::SHARE_TYPE_REMOTE) {
52
+            if (isset($suggestedTarget)) {
53
+                return $suggestedTarget;
54
+            }
55
+            return $backend->generateTarget($itemSource, false);
56
+        } else {
57
+            if ($shareType == self::SHARE_TYPE_USER) {
58
+                // Share with is a user, so set share type to user and groups
59
+                $shareType = self::$shareTypeUserAndGroups;
60
+            }
61 61
 
62
-			// Check if suggested target exists first
63
-			if (!isset($suggestedTarget)) {
64
-				$suggestedTarget = $itemSource;
65
-			}
66
-			if ($shareType == self::SHARE_TYPE_GROUP) {
67
-				$target = $backend->generateTarget($suggestedTarget, false);
68
-			} else {
69
-				$target = $backend->generateTarget($suggestedTarget, $shareWith);
70
-			}
62
+            // Check if suggested target exists first
63
+            if (!isset($suggestedTarget)) {
64
+                $suggestedTarget = $itemSource;
65
+            }
66
+            if ($shareType == self::SHARE_TYPE_GROUP) {
67
+                $target = $backend->generateTarget($suggestedTarget, false);
68
+            } else {
69
+                $target = $backend->generateTarget($suggestedTarget, $shareWith);
70
+            }
71 71
 
72
-			return $target;
73
-		}
74
-	}
72
+            return $target;
73
+        }
74
+    }
75 75
 
76
-	/**
77
-	 * Delete all reshares and group share children of an item
78
-	 * @param int $parent Id of item to delete
79
-	 * @param bool $excludeParent If true, exclude the parent from the delete (optional)
80
-	 * @param string $uidOwner The user that the parent was shared with (optional)
81
-	 * @param int $newParent new parent for the childrens
82
-	 * @param bool $excludeGroupChildren exclude group children elements
83
-	 */
84
-	public static function delete($parent, $excludeParent = false, $uidOwner = null, $newParent = null, $excludeGroupChildren = false) {
85
-		$ids = array($parent);
86
-		$deletedItems = array();
87
-		$changeParent = array();
88
-		$parents = array($parent);
89
-		while (!empty($parents)) {
90
-			$parents = "'".implode("','", $parents)."'";
91
-			// Check the owner on the first search of reshares, useful for
92
-			// finding and deleting the reshares by a single user of a group share
93
-			$params = array();
94
-			if (count($ids) == 1 && isset($uidOwner)) {
95
-				// FIXME: don't concat $parents, use Docrine's PARAM_INT_ARRAY approach
96
-				$queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' .
97
-					'`item_target`, `file_target`, `parent` ' .
98
-					'FROM `*PREFIX*share` ' .
99
-					'WHERE `parent` IN ('.$parents.') AND `uid_owner` = ? ';
100
-				$params[] = $uidOwner;
101
-			} else {
102
-				$queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' .
103
-					'`item_target`, `file_target`, `parent`, `uid_owner` ' .
104
-					'FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') ';
105
-			}
106
-			if ($excludeGroupChildren) {
107
-				$queryString .= ' AND `share_type` != ?';
108
-				$params[] = self::$shareTypeGroupUserUnique;
109
-			}
110
-			$query = \OC_DB::prepare($queryString);
111
-			$result = $query->execute($params);
112
-			// Reset parents array, only go through loop again if items are found
113
-			$parents = array();
114
-			while ($item = $result->fetchRow()) {
115
-				$tmpItem = array(
116
-					'id' => $item['id'],
117
-					'shareWith' => $item['share_with'],
118
-					'itemTarget' => $item['item_target'],
119
-					'itemType' => $item['item_type'],
120
-					'shareType' => (int)$item['share_type'],
121
-				);
122
-				if (isset($item['file_target'])) {
123
-					$tmpItem['fileTarget'] = $item['file_target'];
124
-				}
125
-				// if we have a new parent for the child we remember the child
126
-				// to update the parent, if not we add it to the list of items
127
-				// which should be deleted
128
-				if ($newParent !== null) {
129
-					$changeParent[] = $item['id'];
130
-				} else {
131
-					$deletedItems[] = $tmpItem;
132
-					$ids[] = $item['id'];
133
-					$parents[] = $item['id'];
134
-				}
135
-			}
136
-		}
137
-		if ($excludeParent) {
138
-			unset($ids[0]);
139
-		}
76
+    /**
77
+     * Delete all reshares and group share children of an item
78
+     * @param int $parent Id of item to delete
79
+     * @param bool $excludeParent If true, exclude the parent from the delete (optional)
80
+     * @param string $uidOwner The user that the parent was shared with (optional)
81
+     * @param int $newParent new parent for the childrens
82
+     * @param bool $excludeGroupChildren exclude group children elements
83
+     */
84
+    public static function delete($parent, $excludeParent = false, $uidOwner = null, $newParent = null, $excludeGroupChildren = false) {
85
+        $ids = array($parent);
86
+        $deletedItems = array();
87
+        $changeParent = array();
88
+        $parents = array($parent);
89
+        while (!empty($parents)) {
90
+            $parents = "'".implode("','", $parents)."'";
91
+            // Check the owner on the first search of reshares, useful for
92
+            // finding and deleting the reshares by a single user of a group share
93
+            $params = array();
94
+            if (count($ids) == 1 && isset($uidOwner)) {
95
+                // FIXME: don't concat $parents, use Docrine's PARAM_INT_ARRAY approach
96
+                $queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' .
97
+                    '`item_target`, `file_target`, `parent` ' .
98
+                    'FROM `*PREFIX*share` ' .
99
+                    'WHERE `parent` IN ('.$parents.') AND `uid_owner` = ? ';
100
+                $params[] = $uidOwner;
101
+            } else {
102
+                $queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' .
103
+                    '`item_target`, `file_target`, `parent`, `uid_owner` ' .
104
+                    'FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') ';
105
+            }
106
+            if ($excludeGroupChildren) {
107
+                $queryString .= ' AND `share_type` != ?';
108
+                $params[] = self::$shareTypeGroupUserUnique;
109
+            }
110
+            $query = \OC_DB::prepare($queryString);
111
+            $result = $query->execute($params);
112
+            // Reset parents array, only go through loop again if items are found
113
+            $parents = array();
114
+            while ($item = $result->fetchRow()) {
115
+                $tmpItem = array(
116
+                    'id' => $item['id'],
117
+                    'shareWith' => $item['share_with'],
118
+                    'itemTarget' => $item['item_target'],
119
+                    'itemType' => $item['item_type'],
120
+                    'shareType' => (int)$item['share_type'],
121
+                );
122
+                if (isset($item['file_target'])) {
123
+                    $tmpItem['fileTarget'] = $item['file_target'];
124
+                }
125
+                // if we have a new parent for the child we remember the child
126
+                // to update the parent, if not we add it to the list of items
127
+                // which should be deleted
128
+                if ($newParent !== null) {
129
+                    $changeParent[] = $item['id'];
130
+                } else {
131
+                    $deletedItems[] = $tmpItem;
132
+                    $ids[] = $item['id'];
133
+                    $parents[] = $item['id'];
134
+                }
135
+            }
136
+        }
137
+        if ($excludeParent) {
138
+            unset($ids[0]);
139
+        }
140 140
 
141
-		if (!empty($changeParent)) {
142
-			$idList = "'".implode("','", $changeParent)."'";
143
-			$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` IN ('.$idList.')');
144
-			$query->execute(array($newParent));
145
-		}
141
+        if (!empty($changeParent)) {
142
+            $idList = "'".implode("','", $changeParent)."'";
143
+            $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` IN ('.$idList.')');
144
+            $query->execute(array($newParent));
145
+        }
146 146
 
147
-		if (!empty($ids)) {
148
-			$idList = "'".implode("','", $ids)."'";
149
-			$query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$idList.')');
150
-			$query->execute();
151
-		}
147
+        if (!empty($ids)) {
148
+            $idList = "'".implode("','", $ids)."'";
149
+            $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$idList.')');
150
+            $query->execute();
151
+        }
152 152
 
153
-		return $deletedItems;
154
-	}
153
+        return $deletedItems;
154
+    }
155 155
 
156
-	/**
157
-	 * get default expire settings defined by the admin
158
-	 * @return array contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays'
159
-	 */
160
-	public static function getDefaultExpireSetting() {
156
+    /**
157
+     * get default expire settings defined by the admin
158
+     * @return array contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays'
159
+     */
160
+    public static function getDefaultExpireSetting() {
161 161
 
162
-		$config = \OC::$server->getConfig();
162
+        $config = \OC::$server->getConfig();
163 163
 
164
-		$defaultExpireSettings = array('defaultExpireDateSet' => false);
164
+        $defaultExpireSettings = array('defaultExpireDateSet' => false);
165 165
 
166
-		// get default expire settings
167
-		$defaultExpireDate = $config->getAppValue('core', 'shareapi_default_expire_date', 'no');
168
-		if ($defaultExpireDate === 'yes') {
169
-			$enforceExpireDate = $config->getAppValue('core', 'shareapi_enforce_expire_date', 'no');
170
-			$defaultExpireSettings['defaultExpireDateSet'] = true;
171
-			$defaultExpireSettings['expireAfterDays'] = (int)($config->getAppValue('core', 'shareapi_expire_after_n_days', '7'));
172
-			$defaultExpireSettings['enforceExpireDate'] = $enforceExpireDate === 'yes';
173
-		}
166
+        // get default expire settings
167
+        $defaultExpireDate = $config->getAppValue('core', 'shareapi_default_expire_date', 'no');
168
+        if ($defaultExpireDate === 'yes') {
169
+            $enforceExpireDate = $config->getAppValue('core', 'shareapi_enforce_expire_date', 'no');
170
+            $defaultExpireSettings['defaultExpireDateSet'] = true;
171
+            $defaultExpireSettings['expireAfterDays'] = (int)($config->getAppValue('core', 'shareapi_expire_after_n_days', '7'));
172
+            $defaultExpireSettings['enforceExpireDate'] = $enforceExpireDate === 'yes';
173
+        }
174 174
 
175
-		return $defaultExpireSettings;
176
-	}
175
+        return $defaultExpireSettings;
176
+    }
177 177
 
178
-	public static function calcExpireDate() {
179
-		$expireAfter = \OC\Share\Share::getExpireInterval() * 24 * 60 * 60;
180
-		$expireAt = time() + $expireAfter;
181
-		$date = new \DateTime();
182
-		$date->setTimestamp($expireAt);
183
-		$date->setTime(0, 0, 0);
184
-		//$dateString = $date->format('Y-m-d') . ' 00:00:00';
178
+    public static function calcExpireDate() {
179
+        $expireAfter = \OC\Share\Share::getExpireInterval() * 24 * 60 * 60;
180
+        $expireAt = time() + $expireAfter;
181
+        $date = new \DateTime();
182
+        $date->setTimestamp($expireAt);
183
+        $date->setTime(0, 0, 0);
184
+        //$dateString = $date->format('Y-m-d') . ' 00:00:00';
185 185
 
186
-		return $date;
186
+        return $date;
187 187
 
188
-	}
188
+    }
189 189
 
190
-	/**
191
-	 * calculate expire date
192
-	 * @param array $defaultExpireSettings contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays'
193
-	 * @param int $creationTime timestamp when the share was created
194
-	 * @param int $userExpireDate expire timestamp set by the user
195
-	 * @return mixed integer timestamp or False
196
-	 */
197
-	public static function calculateExpireDate($defaultExpireSettings, $creationTime, $userExpireDate = null) {
190
+    /**
191
+     * calculate expire date
192
+     * @param array $defaultExpireSettings contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays'
193
+     * @param int $creationTime timestamp when the share was created
194
+     * @param int $userExpireDate expire timestamp set by the user
195
+     * @return mixed integer timestamp or False
196
+     */
197
+    public static function calculateExpireDate($defaultExpireSettings, $creationTime, $userExpireDate = null) {
198 198
 
199
-		$expires = false;
200
-		$defaultExpires = null;
199
+        $expires = false;
200
+        $defaultExpires = null;
201 201
 
202
-		if (!empty($defaultExpireSettings['defaultExpireDateSet'])) {
203
-			$defaultExpires = $creationTime + $defaultExpireSettings['expireAfterDays'] * 86400;
204
-		}
202
+        if (!empty($defaultExpireSettings['defaultExpireDateSet'])) {
203
+            $defaultExpires = $creationTime + $defaultExpireSettings['expireAfterDays'] * 86400;
204
+        }
205 205
 
206 206
 
207
-		if (isset($userExpireDate)) {
208
-			// if the admin decided to enforce the default expire date then we only take
209
-			// the user defined expire date of it is before the default expire date
210
-			if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) {
211
-				$expires = min($userExpireDate, $defaultExpires);
212
-			} else {
213
-				$expires = $userExpireDate;
214
-			}
215
-		} else if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) {
216
-			$expires = $defaultExpires;
217
-		}
207
+        if (isset($userExpireDate)) {
208
+            // if the admin decided to enforce the default expire date then we only take
209
+            // the user defined expire date of it is before the default expire date
210
+            if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) {
211
+                $expires = min($userExpireDate, $defaultExpires);
212
+            } else {
213
+                $expires = $userExpireDate;
214
+            }
215
+        } else if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) {
216
+            $expires = $defaultExpires;
217
+        }
218 218
 
219
-		return $expires;
220
-	}
219
+        return $expires;
220
+    }
221 221
 
222
-	/**
223
-	 * Strips away a potential file names and trailing slashes:
224
-	 * - http://localhost
225
-	 * - http://localhost/
226
-	 * - http://localhost/index.php
227
-	 * - http://localhost/index.php/s/{shareToken}
228
-	 *
229
-	 * all return: http://localhost
230
-	 *
231
-	 * @param string $remote
232
-	 * @return string
233
-	 */
234
-	protected static function fixRemoteURL($remote) {
235
-		$remote = str_replace('\\', '/', $remote);
236
-		if ($fileNamePosition = strpos($remote, '/index.php')) {
237
-			$remote = substr($remote, 0, $fileNamePosition);
238
-		}
239
-		$remote = rtrim($remote, '/');
222
+    /**
223
+     * Strips away a potential file names and trailing slashes:
224
+     * - http://localhost
225
+     * - http://localhost/
226
+     * - http://localhost/index.php
227
+     * - http://localhost/index.php/s/{shareToken}
228
+     *
229
+     * all return: http://localhost
230
+     *
231
+     * @param string $remote
232
+     * @return string
233
+     */
234
+    protected static function fixRemoteURL($remote) {
235
+        $remote = str_replace('\\', '/', $remote);
236
+        if ($fileNamePosition = strpos($remote, '/index.php')) {
237
+            $remote = substr($remote, 0, $fileNamePosition);
238
+        }
239
+        $remote = rtrim($remote, '/');
240 240
 
241
-		return $remote;
242
-	}
241
+        return $remote;
242
+    }
243 243
 
244
-	/**
245
-	 * split user and remote from federated cloud id
246
-	 *
247
-	 * @param string $id
248
-	 * @return string[]
249
-	 * @throws HintException
250
-	 */
251
-	public static function splitUserRemote($id) {
252
-		try {
253
-			$cloudId = \OC::$server->getCloudIdManager()->resolveCloudId($id);
254
-			return [$cloudId->getUser(), $cloudId->getRemote()];
255
-		} catch (\InvalidArgumentException $e) {
256
-			$l = \OC::$server->getL10N('core');
257
-			$hint = $l->t('Invalid Federated Cloud ID');
258
-			throw new HintException('Invalid Federated Cloud ID', $hint, 0, $e);
259
-		}
260
-	}
244
+    /**
245
+     * split user and remote from federated cloud id
246
+     *
247
+     * @param string $id
248
+     * @return string[]
249
+     * @throws HintException
250
+     */
251
+    public static function splitUserRemote($id) {
252
+        try {
253
+            $cloudId = \OC::$server->getCloudIdManager()->resolveCloudId($id);
254
+            return [$cloudId->getUser(), $cloudId->getRemote()];
255
+        } catch (\InvalidArgumentException $e) {
256
+            $l = \OC::$server->getL10N('core');
257
+            $hint = $l->t('Invalid Federated Cloud ID');
258
+            throw new HintException('Invalid Federated Cloud ID', $hint, 0, $e);
259
+        }
260
+    }
261 261
 
262
-	/**
263
-	 * check if two federated cloud IDs refer to the same user
264
-	 *
265
-	 * @param string $user1
266
-	 * @param string $server1
267
-	 * @param string $user2
268
-	 * @param string $server2
269
-	 * @return bool true if both users and servers are the same
270
-	 */
271
-	public static function isSameUserOnSameServer($user1, $server1, $user2, $server2) {
272
-		$normalizedServer1 = strtolower(\OC\Share\Share::removeProtocolFromUrl($server1));
273
-		$normalizedServer2 = strtolower(\OC\Share\Share::removeProtocolFromUrl($server2));
262
+    /**
263
+     * check if two federated cloud IDs refer to the same user
264
+     *
265
+     * @param string $user1
266
+     * @param string $server1
267
+     * @param string $user2
268
+     * @param string $server2
269
+     * @return bool true if both users and servers are the same
270
+     */
271
+    public static function isSameUserOnSameServer($user1, $server1, $user2, $server2) {
272
+        $normalizedServer1 = strtolower(\OC\Share\Share::removeProtocolFromUrl($server1));
273
+        $normalizedServer2 = strtolower(\OC\Share\Share::removeProtocolFromUrl($server2));
274 274
 
275
-		if (rtrim($normalizedServer1, '/') === rtrim($normalizedServer2, '/')) {
276
-			// FIXME this should be a method in the user management instead
277
-			\OCP\Util::emitHook(
278
-					'\OCA\Files_Sharing\API\Server2Server',
279
-					'preLoginNameUsedAsUserName',
280
-					array('uid' => &$user1)
281
-			);
282
-			\OCP\Util::emitHook(
283
-					'\OCA\Files_Sharing\API\Server2Server',
284
-					'preLoginNameUsedAsUserName',
285
-					array('uid' => &$user2)
286
-			);
275
+        if (rtrim($normalizedServer1, '/') === rtrim($normalizedServer2, '/')) {
276
+            // FIXME this should be a method in the user management instead
277
+            \OCP\Util::emitHook(
278
+                    '\OCA\Files_Sharing\API\Server2Server',
279
+                    'preLoginNameUsedAsUserName',
280
+                    array('uid' => &$user1)
281
+            );
282
+            \OCP\Util::emitHook(
283
+                    '\OCA\Files_Sharing\API\Server2Server',
284
+                    'preLoginNameUsedAsUserName',
285
+                    array('uid' => &$user2)
286
+            );
287 287
 
288
-			if ($user1 === $user2) {
289
-				return true;
290
-			}
291
-		}
288
+            if ($user1 === $user2) {
289
+                return true;
290
+            }
291
+        }
292 292
 
293
-		return false;
294
-	}
293
+        return false;
294
+    }
295 295
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -93,14 +93,14 @@  discard block
 block discarded – undo
93 93
 			$params = array();
94 94
 			if (count($ids) == 1 && isset($uidOwner)) {
95 95
 				// FIXME: don't concat $parents, use Docrine's PARAM_INT_ARRAY approach
96
-				$queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' .
97
-					'`item_target`, `file_target`, `parent` ' .
98
-					'FROM `*PREFIX*share` ' .
96
+				$queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, '.
97
+					'`item_target`, `file_target`, `parent` '.
98
+					'FROM `*PREFIX*share` '.
99 99
 					'WHERE `parent` IN ('.$parents.') AND `uid_owner` = ? ';
100 100
 				$params[] = $uidOwner;
101 101
 			} else {
102
-				$queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' .
103
-					'`item_target`, `file_target`, `parent`, `uid_owner` ' .
102
+				$queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, '.
103
+					'`item_target`, `file_target`, `parent`, `uid_owner` '.
104 104
 					'FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') ';
105 105
 			}
106 106
 			if ($excludeGroupChildren) {
@@ -117,7 +117,7 @@  discard block
 block discarded – undo
117 117
 					'shareWith' => $item['share_with'],
118 118
 					'itemTarget' => $item['item_target'],
119 119
 					'itemType' => $item['item_type'],
120
-					'shareType' => (int)$item['share_type'],
120
+					'shareType' => (int) $item['share_type'],
121 121
 				);
122 122
 				if (isset($item['file_target'])) {
123 123
 					$tmpItem['fileTarget'] = $item['file_target'];
@@ -168,7 +168,7 @@  discard block
 block discarded – undo
168 168
 		if ($defaultExpireDate === 'yes') {
169 169
 			$enforceExpireDate = $config->getAppValue('core', 'shareapi_enforce_expire_date', 'no');
170 170
 			$defaultExpireSettings['defaultExpireDateSet'] = true;
171
-			$defaultExpireSettings['expireAfterDays'] = (int)($config->getAppValue('core', 'shareapi_expire_after_n_days', '7'));
171
+			$defaultExpireSettings['expireAfterDays'] = (int) ($config->getAppValue('core', 'shareapi_expire_after_n_days', '7'));
172 172
 			$defaultExpireSettings['enforceExpireDate'] = $enforceExpireDate === 'yes';
173 173
 		}
174 174
 
Please login to merge, or discard this patch.
lib/private/Memcache/Redis.php 2 patches
Indentation   +146 added lines, -146 removed lines patch added patch discarded remove patch
@@ -31,151 +31,151 @@
 block discarded – undo
31 31
 use OCP\IMemcacheTTL;
32 32
 
33 33
 class Redis extends Cache implements IMemcacheTTL {
34
-	/**
35
-	 * @var \Redis $cache
36
-	 */
37
-	private static $cache = null;
38
-
39
-	public function __construct($prefix = '') {
40
-		parent::__construct($prefix);
41
-		if (is_null(self::$cache)) {
42
-			self::$cache = \OC::$server->getGetRedisFactory()->getInstance();
43
-		}
44
-	}
45
-
46
-	/**
47
-	 * entries in redis get namespaced to prevent collisions between ownCloud instances and users
48
-	 */
49
-	protected function getNameSpace() {
50
-		return $this->prefix;
51
-	}
52
-
53
-	public function get($key) {
54
-		$result = self::$cache->get($this->getNameSpace() . $key);
55
-		if ($result === false && !self::$cache->exists($this->getNameSpace() . $key)) {
56
-			return null;
57
-		} else {
58
-			return json_decode($result, true);
59
-		}
60
-	}
61
-
62
-	public function set($key, $value, $ttl = 0) {
63
-		if ($ttl > 0) {
64
-			return self::$cache->setex($this->getNameSpace() . $key, $ttl, json_encode($value));
65
-		} else {
66
-			return self::$cache->set($this->getNameSpace() . $key, json_encode($value));
67
-		}
68
-	}
69
-
70
-	public function hasKey($key) {
71
-		return self::$cache->exists($this->getNameSpace() . $key);
72
-	}
73
-
74
-	public function remove($key) {
75
-		if (self::$cache->del($this->getNameSpace() . $key)) {
76
-			return true;
77
-		} else {
78
-			return false;
79
-		}
80
-	}
81
-
82
-	public function clear($prefix = '') {
83
-		$prefix = $this->getNameSpace() . $prefix . '*';
84
-		$keys = self::$cache->keys($prefix);
85
-		$deleted = self::$cache->del($keys);
86
-
87
-		return count($keys) === $deleted;
88
-	}
89
-
90
-	/**
91
-	 * Set a value in the cache if it's not already stored
92
-	 *
93
-	 * @param string $key
94
-	 * @param mixed $value
95
-	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
96
-	 * @return bool
97
-	 */
98
-	public function add($key, $value, $ttl = 0) {
99
-		// don't encode ints for inc/dec
100
-		if (!is_int($value)) {
101
-			$value = json_encode($value);
102
-		}
103
-		return self::$cache->setnx($this->getPrefix() . $key, $value);
104
-	}
105
-
106
-	/**
107
-	 * Increase a stored number
108
-	 *
109
-	 * @param string $key
110
-	 * @param int $step
111
-	 * @return int | bool
112
-	 */
113
-	public function inc($key, $step = 1) {
114
-		return self::$cache->incrBy($this->getNameSpace() . $key, $step);
115
-	}
116
-
117
-	/**
118
-	 * Decrease a stored number
119
-	 *
120
-	 * @param string $key
121
-	 * @param int $step
122
-	 * @return int | bool
123
-	 */
124
-	public function dec($key, $step = 1) {
125
-		if (!$this->hasKey($key)) {
126
-			return false;
127
-		}
128
-		return self::$cache->decrBy($this->getNameSpace() . $key, $step);
129
-	}
130
-
131
-	/**
132
-	 * Compare and set
133
-	 *
134
-	 * @param string $key
135
-	 * @param mixed $old
136
-	 * @param mixed $new
137
-	 * @return bool
138
-	 */
139
-	public function cas($key, $old, $new) {
140
-		if (!is_int($new)) {
141
-			$new = json_encode($new);
142
-		}
143
-		self::$cache->watch($this->getNameSpace() . $key);
144
-		if ($this->get($key) === $old) {
145
-			$result = self::$cache->multi()
146
-				->set($this->getNameSpace() . $key, $new)
147
-				->exec();
148
-			return $result !== false;
149
-		}
150
-		self::$cache->unwatch();
151
-		return false;
152
-	}
153
-
154
-	/**
155
-	 * Compare and delete
156
-	 *
157
-	 * @param string $key
158
-	 * @param mixed $old
159
-	 * @return bool
160
-	 */
161
-	public function cad($key, $old) {
162
-		self::$cache->watch($this->getNameSpace() . $key);
163
-		if ($this->get($key) === $old) {
164
-			$result = self::$cache->multi()
165
-				->del($this->getNameSpace() . $key)
166
-				->exec();
167
-			return $result !== false;
168
-		}
169
-		self::$cache->unwatch();
170
-		return false;
171
-	}
172
-
173
-	public function setTTL($key, $ttl) {
174
-		self::$cache->expire($this->getNameSpace() . $key, $ttl);
175
-	}
176
-
177
-	static public function isAvailable() {
178
-		return \OC::$server->getGetRedisFactory()->isAvailable();
179
-	}
34
+    /**
35
+     * @var \Redis $cache
36
+     */
37
+    private static $cache = null;
38
+
39
+    public function __construct($prefix = '') {
40
+        parent::__construct($prefix);
41
+        if (is_null(self::$cache)) {
42
+            self::$cache = \OC::$server->getGetRedisFactory()->getInstance();
43
+        }
44
+    }
45
+
46
+    /**
47
+     * entries in redis get namespaced to prevent collisions between ownCloud instances and users
48
+     */
49
+    protected function getNameSpace() {
50
+        return $this->prefix;
51
+    }
52
+
53
+    public function get($key) {
54
+        $result = self::$cache->get($this->getNameSpace() . $key);
55
+        if ($result === false && !self::$cache->exists($this->getNameSpace() . $key)) {
56
+            return null;
57
+        } else {
58
+            return json_decode($result, true);
59
+        }
60
+    }
61
+
62
+    public function set($key, $value, $ttl = 0) {
63
+        if ($ttl > 0) {
64
+            return self::$cache->setex($this->getNameSpace() . $key, $ttl, json_encode($value));
65
+        } else {
66
+            return self::$cache->set($this->getNameSpace() . $key, json_encode($value));
67
+        }
68
+    }
69
+
70
+    public function hasKey($key) {
71
+        return self::$cache->exists($this->getNameSpace() . $key);
72
+    }
73
+
74
+    public function remove($key) {
75
+        if (self::$cache->del($this->getNameSpace() . $key)) {
76
+            return true;
77
+        } else {
78
+            return false;
79
+        }
80
+    }
81
+
82
+    public function clear($prefix = '') {
83
+        $prefix = $this->getNameSpace() . $prefix . '*';
84
+        $keys = self::$cache->keys($prefix);
85
+        $deleted = self::$cache->del($keys);
86
+
87
+        return count($keys) === $deleted;
88
+    }
89
+
90
+    /**
91
+     * Set a value in the cache if it's not already stored
92
+     *
93
+     * @param string $key
94
+     * @param mixed $value
95
+     * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
96
+     * @return bool
97
+     */
98
+    public function add($key, $value, $ttl = 0) {
99
+        // don't encode ints for inc/dec
100
+        if (!is_int($value)) {
101
+            $value = json_encode($value);
102
+        }
103
+        return self::$cache->setnx($this->getPrefix() . $key, $value);
104
+    }
105
+
106
+    /**
107
+     * Increase a stored number
108
+     *
109
+     * @param string $key
110
+     * @param int $step
111
+     * @return int | bool
112
+     */
113
+    public function inc($key, $step = 1) {
114
+        return self::$cache->incrBy($this->getNameSpace() . $key, $step);
115
+    }
116
+
117
+    /**
118
+     * Decrease a stored number
119
+     *
120
+     * @param string $key
121
+     * @param int $step
122
+     * @return int | bool
123
+     */
124
+    public function dec($key, $step = 1) {
125
+        if (!$this->hasKey($key)) {
126
+            return false;
127
+        }
128
+        return self::$cache->decrBy($this->getNameSpace() . $key, $step);
129
+    }
130
+
131
+    /**
132
+     * Compare and set
133
+     *
134
+     * @param string $key
135
+     * @param mixed $old
136
+     * @param mixed $new
137
+     * @return bool
138
+     */
139
+    public function cas($key, $old, $new) {
140
+        if (!is_int($new)) {
141
+            $new = json_encode($new);
142
+        }
143
+        self::$cache->watch($this->getNameSpace() . $key);
144
+        if ($this->get($key) === $old) {
145
+            $result = self::$cache->multi()
146
+                ->set($this->getNameSpace() . $key, $new)
147
+                ->exec();
148
+            return $result !== false;
149
+        }
150
+        self::$cache->unwatch();
151
+        return false;
152
+    }
153
+
154
+    /**
155
+     * Compare and delete
156
+     *
157
+     * @param string $key
158
+     * @param mixed $old
159
+     * @return bool
160
+     */
161
+    public function cad($key, $old) {
162
+        self::$cache->watch($this->getNameSpace() . $key);
163
+        if ($this->get($key) === $old) {
164
+            $result = self::$cache->multi()
165
+                ->del($this->getNameSpace() . $key)
166
+                ->exec();
167
+            return $result !== false;
168
+        }
169
+        self::$cache->unwatch();
170
+        return false;
171
+    }
172
+
173
+    public function setTTL($key, $ttl) {
174
+        self::$cache->expire($this->getNameSpace() . $key, $ttl);
175
+    }
176
+
177
+    static public function isAvailable() {
178
+        return \OC::$server->getGetRedisFactory()->isAvailable();
179
+    }
180 180
 }
181 181
 
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -51,8 +51,8 @@  discard block
 block discarded – undo
51 51
 	}
52 52
 
53 53
 	public function get($key) {
54
-		$result = self::$cache->get($this->getNameSpace() . $key);
55
-		if ($result === false && !self::$cache->exists($this->getNameSpace() . $key)) {
54
+		$result = self::$cache->get($this->getNameSpace().$key);
55
+		if ($result === false && !self::$cache->exists($this->getNameSpace().$key)) {
56 56
 			return null;
57 57
 		} else {
58 58
 			return json_decode($result, true);
@@ -61,18 +61,18 @@  discard block
 block discarded – undo
61 61
 
62 62
 	public function set($key, $value, $ttl = 0) {
63 63
 		if ($ttl > 0) {
64
-			return self::$cache->setex($this->getNameSpace() . $key, $ttl, json_encode($value));
64
+			return self::$cache->setex($this->getNameSpace().$key, $ttl, json_encode($value));
65 65
 		} else {
66
-			return self::$cache->set($this->getNameSpace() . $key, json_encode($value));
66
+			return self::$cache->set($this->getNameSpace().$key, json_encode($value));
67 67
 		}
68 68
 	}
69 69
 
70 70
 	public function hasKey($key) {
71
-		return self::$cache->exists($this->getNameSpace() . $key);
71
+		return self::$cache->exists($this->getNameSpace().$key);
72 72
 	}
73 73
 
74 74
 	public function remove($key) {
75
-		if (self::$cache->del($this->getNameSpace() . $key)) {
75
+		if (self::$cache->del($this->getNameSpace().$key)) {
76 76
 			return true;
77 77
 		} else {
78 78
 			return false;
@@ -80,7 +80,7 @@  discard block
 block discarded – undo
80 80
 	}
81 81
 
82 82
 	public function clear($prefix = '') {
83
-		$prefix = $this->getNameSpace() . $prefix . '*';
83
+		$prefix = $this->getNameSpace().$prefix.'*';
84 84
 		$keys = self::$cache->keys($prefix);
85 85
 		$deleted = self::$cache->del($keys);
86 86
 
@@ -100,7 +100,7 @@  discard block
 block discarded – undo
100 100
 		if (!is_int($value)) {
101 101
 			$value = json_encode($value);
102 102
 		}
103
-		return self::$cache->setnx($this->getPrefix() . $key, $value);
103
+		return self::$cache->setnx($this->getPrefix().$key, $value);
104 104
 	}
105 105
 
106 106
 	/**
@@ -111,7 +111,7 @@  discard block
 block discarded – undo
111 111
 	 * @return int | bool
112 112
 	 */
113 113
 	public function inc($key, $step = 1) {
114
-		return self::$cache->incrBy($this->getNameSpace() . $key, $step);
114
+		return self::$cache->incrBy($this->getNameSpace().$key, $step);
115 115
 	}
116 116
 
117 117
 	/**
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
 		if (!$this->hasKey($key)) {
126 126
 			return false;
127 127
 		}
128
-		return self::$cache->decrBy($this->getNameSpace() . $key, $step);
128
+		return self::$cache->decrBy($this->getNameSpace().$key, $step);
129 129
 	}
130 130
 
131 131
 	/**
@@ -140,10 +140,10 @@  discard block
 block discarded – undo
140 140
 		if (!is_int($new)) {
141 141
 			$new = json_encode($new);
142 142
 		}
143
-		self::$cache->watch($this->getNameSpace() . $key);
143
+		self::$cache->watch($this->getNameSpace().$key);
144 144
 		if ($this->get($key) === $old) {
145 145
 			$result = self::$cache->multi()
146
-				->set($this->getNameSpace() . $key, $new)
146
+				->set($this->getNameSpace().$key, $new)
147 147
 				->exec();
148 148
 			return $result !== false;
149 149
 		}
@@ -159,10 +159,10 @@  discard block
 block discarded – undo
159 159
 	 * @return bool
160 160
 	 */
161 161
 	public function cad($key, $old) {
162
-		self::$cache->watch($this->getNameSpace() . $key);
162
+		self::$cache->watch($this->getNameSpace().$key);
163 163
 		if ($this->get($key) === $old) {
164 164
 			$result = self::$cache->multi()
165
-				->del($this->getNameSpace() . $key)
165
+				->del($this->getNameSpace().$key)
166 166
 				->exec();
167 167
 			return $result !== false;
168 168
 		}
@@ -171,7 +171,7 @@  discard block
 block discarded – undo
171 171
 	}
172 172
 
173 173
 	public function setTTL($key, $ttl) {
174
-		self::$cache->expire($this->getNameSpace() . $key, $ttl);
174
+		self::$cache->expire($this->getNameSpace().$key, $ttl);
175 175
 	}
176 176
 
177 177
 	static public function isAvailable() {
Please login to merge, or discard this patch.
lib/private/Encryption/Util.php 1 patch
Indentation   +366 added lines, -366 removed lines patch added patch discarded remove patch
@@ -38,371 +38,371 @@
 block discarded – undo
38 38
 
39 39
 class Util {
40 40
 
41
-	const HEADER_START = 'HBEGIN';
42
-	const HEADER_END = 'HEND';
43
-	const HEADER_PADDING_CHAR = '-';
44
-
45
-	const HEADER_ENCRYPTION_MODULE_KEY = 'oc_encryption_module';
46
-
47
-	/**
48
-	 * block size will always be 8192 for a PHP stream
49
-	 * @see https://bugs.php.net/bug.php?id=21641
50
-	 * @var integer
51
-	 */
52
-	protected $headerSize = 8192;
53
-
54
-	/**
55
-	 * block size will always be 8192 for a PHP stream
56
-	 * @see https://bugs.php.net/bug.php?id=21641
57
-	 * @var integer
58
-	 */
59
-	protected $blockSize = 8192;
60
-
61
-	/** @var View */
62
-	protected $rootView;
63
-
64
-	/** @var array */
65
-	protected $ocHeaderKeys;
66
-
67
-	/** @var \OC\User\Manager */
68
-	protected $userManager;
69
-
70
-	/** @var IConfig */
71
-	protected $config;
72
-
73
-	/** @var array paths excluded from encryption */
74
-	protected $excludedPaths;
75
-
76
-	/** @var \OC\Group\Manager $manager */
77
-	protected $groupManager;
78
-
79
-	/**
80
-	 *
81
-	 * @param View $rootView
82
-	 * @param \OC\User\Manager $userManager
83
-	 * @param \OC\Group\Manager $groupManager
84
-	 * @param IConfig $config
85
-	 */
86
-	public function __construct(
87
-		View $rootView,
88
-		\OC\User\Manager $userManager,
89
-		\OC\Group\Manager $groupManager,
90
-		IConfig $config) {
91
-
92
-		$this->ocHeaderKeys = [
93
-			self::HEADER_ENCRYPTION_MODULE_KEY
94
-		];
95
-
96
-		$this->rootView = $rootView;
97
-		$this->userManager = $userManager;
98
-		$this->groupManager = $groupManager;
99
-		$this->config = $config;
100
-
101
-		$this->excludedPaths[] = 'files_encryption';
102
-		$this->excludedPaths[] = 'appdata_' . $config->getSystemValue('instanceid', null);
103
-		$this->excludedPaths[] = 'files_external';
104
-	}
105
-
106
-	/**
107
-	 * read encryption module ID from header
108
-	 *
109
-	 * @param array $header
110
-	 * @return string
111
-	 * @throws ModuleDoesNotExistsException
112
-	 */
113
-	public function getEncryptionModuleId(array $header = null) {
114
-		$id = '';
115
-		$encryptionModuleKey = self::HEADER_ENCRYPTION_MODULE_KEY;
116
-
117
-		if (isset($header[$encryptionModuleKey])) {
118
-			$id = $header[$encryptionModuleKey];
119
-		} elseif (isset($header['cipher'])) {
120
-			if (class_exists('\OCA\Encryption\Crypto\Encryption')) {
121
-				// fall back to default encryption if the user migrated from
122
-				// ownCloud <= 8.0 with the old encryption
123
-				$id = \OCA\Encryption\Crypto\Encryption::ID;
124
-			} else {
125
-				throw new ModuleDoesNotExistsException('Default encryption module missing');
126
-			}
127
-		}
128
-
129
-		return $id;
130
-	}
131
-
132
-	/**
133
-	 * create header for encrypted file
134
-	 *
135
-	 * @param array $headerData
136
-	 * @param IEncryptionModule $encryptionModule
137
-	 * @return string
138
-	 * @throws EncryptionHeaderToLargeException if header has to many arguments
139
-	 * @throws EncryptionHeaderKeyExistsException if header key is already in use
140
-	 */
141
-	public function createHeader(array $headerData, IEncryptionModule $encryptionModule) {
142
-		$header = self::HEADER_START . ':' . self::HEADER_ENCRYPTION_MODULE_KEY . ':' . $encryptionModule->getId() . ':';
143
-		foreach ($headerData as $key => $value) {
144
-			if (in_array($key, $this->ocHeaderKeys)) {
145
-				throw new EncryptionHeaderKeyExistsException($key);
146
-			}
147
-			$header .= $key . ':' . $value . ':';
148
-		}
149
-		$header .= self::HEADER_END;
150
-
151
-		if (strlen($header) > $this->getHeaderSize()) {
152
-			throw new EncryptionHeaderToLargeException();
153
-		}
154
-
155
-		$paddedHeader = str_pad($header, $this->headerSize, self::HEADER_PADDING_CHAR, STR_PAD_RIGHT);
156
-
157
-		return $paddedHeader;
158
-	}
159
-
160
-	/**
161
-	 * go recursively through a dir and collect all files and sub files.
162
-	 *
163
-	 * @param string $dir relative to the users files folder
164
-	 * @return array with list of files relative to the users files folder
165
-	 */
166
-	public function getAllFiles($dir) {
167
-		$result = array();
168
-		$dirList = array($dir);
169
-
170
-		while ($dirList) {
171
-			$dir = array_pop($dirList);
172
-			$content = $this->rootView->getDirectoryContent($dir);
173
-
174
-			foreach ($content as $c) {
175
-				if ($c->getType() === 'dir') {
176
-					$dirList[] = $c->getPath();
177
-				} else {
178
-					$result[] =  $c->getPath();
179
-				}
180
-			}
181
-
182
-		}
183
-
184
-		return $result;
185
-	}
186
-
187
-	/**
188
-	 * check if it is a file uploaded by the user stored in data/user/files
189
-	 * or a metadata file
190
-	 *
191
-	 * @param string $path relative to the data/ folder
192
-	 * @return boolean
193
-	 */
194
-	public function isFile($path) {
195
-		$parts = explode('/', Filesystem::normalizePath($path), 4);
196
-		if (isset($parts[2]) && $parts[2] === 'files') {
197
-			return true;
198
-		}
199
-		return false;
200
-	}
201
-
202
-	/**
203
-	 * return size of encryption header
204
-	 *
205
-	 * @return integer
206
-	 */
207
-	public function getHeaderSize() {
208
-		return $this->headerSize;
209
-	}
210
-
211
-	/**
212
-	 * return size of block read by a PHP stream
213
-	 *
214
-	 * @return integer
215
-	 */
216
-	public function getBlockSize() {
217
-		return $this->blockSize;
218
-	}
219
-
220
-	/**
221
-	 * get the owner and the path for the file relative to the owners files folder
222
-	 *
223
-	 * @param string $path
224
-	 * @return array
225
-	 * @throws \BadMethodCallException
226
-	 */
227
-	public function getUidAndFilename($path) {
228
-
229
-		$parts = explode('/', $path);
230
-		$uid = '';
231
-		if (count($parts) > 2) {
232
-			$uid = $parts[1];
233
-		}
234
-		if (!$this->userManager->userExists($uid)) {
235
-			throw new \BadMethodCallException(
236
-				'path needs to be relative to the system wide data folder and point to a user specific file'
237
-			);
238
-		}
239
-
240
-		$ownerPath = implode('/', array_slice($parts, 2));
241
-
242
-		return array($uid, Filesystem::normalizePath($ownerPath));
243
-
244
-	}
245
-
246
-	/**
247
-	 * Remove .path extension from a file path
248
-	 * @param string $path Path that may identify a .part file
249
-	 * @return string File path without .part extension
250
-	 * @note this is needed for reusing keys
251
-	 */
252
-	public function stripPartialFileExtension($path) {
253
-		$extension = pathinfo($path, PATHINFO_EXTENSION);
254
-
255
-		if ( $extension === 'part') {
256
-
257
-			$newLength = strlen($path) - 5; // 5 = strlen(".part")
258
-			$fPath = substr($path, 0, $newLength);
259
-
260
-			// if path also contains a transaction id, we remove it too
261
-			$extension = pathinfo($fPath, PATHINFO_EXTENSION);
262
-			if(substr($extension, 0, 12) === 'ocTransferId') { // 12 = strlen("ocTransferId")
263
-				$newLength = strlen($fPath) - strlen($extension) -1;
264
-				$fPath = substr($fPath, 0, $newLength);
265
-			}
266
-			return $fPath;
267
-
268
-		} else {
269
-			return $path;
270
-		}
271
-	}
272
-
273
-	public function getUserWithAccessToMountPoint($users, $groups) {
274
-		$result = array();
275
-		if (in_array('all', $users)) {
276
-			$result = \OCP\User::getUsers();
277
-		} else {
278
-			$result = array_merge($result, $users);
279
-
280
-			$groupManager = \OC::$server->getGroupManager();
281
-			foreach ($groups as $group) {
282
-				$groupObject = $groupManager->get($group);
283
-				if ($groupObject) {
284
-					$foundUsers = $groupObject->searchUsers('', -1, 0);
285
-					$userIds = [];
286
-					foreach ($foundUsers as $user) {
287
-						$userIds[] = $user->getUID();
288
-					}
289
-					$result = array_merge($result, $userIds);
290
-				}
291
-			}
292
-		}
293
-
294
-		return $result;
295
-	}
296
-
297
-	/**
298
-	 * check if the file is stored on a system wide mount point
299
-	 * @param string $path relative to /data/user with leading '/'
300
-	 * @param string $uid
301
-	 * @return boolean
302
-	 */
303
-	public function isSystemWideMountPoint($path, $uid) {
304
-		if (\OCP\App::isEnabled("files_external")) {
305
-			$mounts = \OC_Mount_Config::getSystemMountPoints();
306
-			foreach ($mounts as $mount) {
307
-				if (strpos($path, '/files/' . $mount['mountpoint']) === 0) {
308
-					if ($this->isMountPointApplicableToUser($mount, $uid)) {
309
-						return true;
310
-					}
311
-				}
312
-			}
313
-		}
314
-		return false;
315
-	}
316
-
317
-	/**
318
-	 * check if mount point is applicable to user
319
-	 *
320
-	 * @param array $mount contains $mount['applicable']['users'], $mount['applicable']['groups']
321
-	 * @param string $uid
322
-	 * @return boolean
323
-	 */
324
-	private function isMountPointApplicableToUser($mount, $uid) {
325
-		$acceptedUids = array('all', $uid);
326
-		// check if mount point is applicable for the user
327
-		$intersection = array_intersect($acceptedUids, $mount['applicable']['users']);
328
-		if (!empty($intersection)) {
329
-			return true;
330
-		}
331
-		// check if mount point is applicable for group where the user is a member
332
-		foreach ($mount['applicable']['groups'] as $gid) {
333
-			if ($this->groupManager->isInGroup($uid, $gid)) {
334
-				return true;
335
-			}
336
-		}
337
-		return false;
338
-	}
339
-
340
-	/**
341
-	 * check if it is a path which is excluded by ownCloud from encryption
342
-	 *
343
-	 * @param string $path
344
-	 * @return boolean
345
-	 */
346
-	public function isExcluded($path) {
347
-		$normalizedPath = Filesystem::normalizePath($path);
348
-		$root = explode('/', $normalizedPath, 4);
349
-		if (count($root) > 1) {
350
-
351
-			// detect alternative key storage root
352
-			$rootDir = $this->getKeyStorageRoot();
353
-			if ($rootDir !== '' &&
354
-				0 === strpos(
355
-					Filesystem::normalizePath($path),
356
-					Filesystem::normalizePath($rootDir)
357
-				)
358
-			) {
359
-				return true;
360
-			}
361
-
362
-
363
-			//detect system wide folders
364
-			if (in_array($root[1], $this->excludedPaths)) {
365
-				return true;
366
-			}
367
-
368
-			// detect user specific folders
369
-			if ($this->userManager->userExists($root[1])
370
-				&& in_array($root[2], $this->excludedPaths)) {
371
-
372
-				return true;
373
-			}
374
-		}
375
-		return false;
376
-	}
377
-
378
-	/**
379
-	 * check if recovery key is enabled for user
380
-	 *
381
-	 * @param string $uid
382
-	 * @return boolean
383
-	 */
384
-	public function recoveryEnabled($uid) {
385
-		$enabled = $this->config->getUserValue($uid, 'encryption', 'recovery_enabled', '0');
386
-
387
-		return $enabled === '1';
388
-	}
389
-
390
-	/**
391
-	 * set new key storage root
392
-	 *
393
-	 * @param string $root new key store root relative to the data folder
394
-	 */
395
-	public function setKeyStorageRoot($root) {
396
-		$this->config->setAppValue('core', 'encryption_key_storage_root', $root);
397
-	}
398
-
399
-	/**
400
-	 * get key storage root
401
-	 *
402
-	 * @return string key storage root
403
-	 */
404
-	public function getKeyStorageRoot() {
405
-		return $this->config->getAppValue('core', 'encryption_key_storage_root', '');
406
-	}
41
+    const HEADER_START = 'HBEGIN';
42
+    const HEADER_END = 'HEND';
43
+    const HEADER_PADDING_CHAR = '-';
44
+
45
+    const HEADER_ENCRYPTION_MODULE_KEY = 'oc_encryption_module';
46
+
47
+    /**
48
+     * block size will always be 8192 for a PHP stream
49
+     * @see https://bugs.php.net/bug.php?id=21641
50
+     * @var integer
51
+     */
52
+    protected $headerSize = 8192;
53
+
54
+    /**
55
+     * block size will always be 8192 for a PHP stream
56
+     * @see https://bugs.php.net/bug.php?id=21641
57
+     * @var integer
58
+     */
59
+    protected $blockSize = 8192;
60
+
61
+    /** @var View */
62
+    protected $rootView;
63
+
64
+    /** @var array */
65
+    protected $ocHeaderKeys;
66
+
67
+    /** @var \OC\User\Manager */
68
+    protected $userManager;
69
+
70
+    /** @var IConfig */
71
+    protected $config;
72
+
73
+    /** @var array paths excluded from encryption */
74
+    protected $excludedPaths;
75
+
76
+    /** @var \OC\Group\Manager $manager */
77
+    protected $groupManager;
78
+
79
+    /**
80
+     *
81
+     * @param View $rootView
82
+     * @param \OC\User\Manager $userManager
83
+     * @param \OC\Group\Manager $groupManager
84
+     * @param IConfig $config
85
+     */
86
+    public function __construct(
87
+        View $rootView,
88
+        \OC\User\Manager $userManager,
89
+        \OC\Group\Manager $groupManager,
90
+        IConfig $config) {
91
+
92
+        $this->ocHeaderKeys = [
93
+            self::HEADER_ENCRYPTION_MODULE_KEY
94
+        ];
95
+
96
+        $this->rootView = $rootView;
97
+        $this->userManager = $userManager;
98
+        $this->groupManager = $groupManager;
99
+        $this->config = $config;
100
+
101
+        $this->excludedPaths[] = 'files_encryption';
102
+        $this->excludedPaths[] = 'appdata_' . $config->getSystemValue('instanceid', null);
103
+        $this->excludedPaths[] = 'files_external';
104
+    }
105
+
106
+    /**
107
+     * read encryption module ID from header
108
+     *
109
+     * @param array $header
110
+     * @return string
111
+     * @throws ModuleDoesNotExistsException
112
+     */
113
+    public function getEncryptionModuleId(array $header = null) {
114
+        $id = '';
115
+        $encryptionModuleKey = self::HEADER_ENCRYPTION_MODULE_KEY;
116
+
117
+        if (isset($header[$encryptionModuleKey])) {
118
+            $id = $header[$encryptionModuleKey];
119
+        } elseif (isset($header['cipher'])) {
120
+            if (class_exists('\OCA\Encryption\Crypto\Encryption')) {
121
+                // fall back to default encryption if the user migrated from
122
+                // ownCloud <= 8.0 with the old encryption
123
+                $id = \OCA\Encryption\Crypto\Encryption::ID;
124
+            } else {
125
+                throw new ModuleDoesNotExistsException('Default encryption module missing');
126
+            }
127
+        }
128
+
129
+        return $id;
130
+    }
131
+
132
+    /**
133
+     * create header for encrypted file
134
+     *
135
+     * @param array $headerData
136
+     * @param IEncryptionModule $encryptionModule
137
+     * @return string
138
+     * @throws EncryptionHeaderToLargeException if header has to many arguments
139
+     * @throws EncryptionHeaderKeyExistsException if header key is already in use
140
+     */
141
+    public function createHeader(array $headerData, IEncryptionModule $encryptionModule) {
142
+        $header = self::HEADER_START . ':' . self::HEADER_ENCRYPTION_MODULE_KEY . ':' . $encryptionModule->getId() . ':';
143
+        foreach ($headerData as $key => $value) {
144
+            if (in_array($key, $this->ocHeaderKeys)) {
145
+                throw new EncryptionHeaderKeyExistsException($key);
146
+            }
147
+            $header .= $key . ':' . $value . ':';
148
+        }
149
+        $header .= self::HEADER_END;
150
+
151
+        if (strlen($header) > $this->getHeaderSize()) {
152
+            throw new EncryptionHeaderToLargeException();
153
+        }
154
+
155
+        $paddedHeader = str_pad($header, $this->headerSize, self::HEADER_PADDING_CHAR, STR_PAD_RIGHT);
156
+
157
+        return $paddedHeader;
158
+    }
159
+
160
+    /**
161
+     * go recursively through a dir and collect all files and sub files.
162
+     *
163
+     * @param string $dir relative to the users files folder
164
+     * @return array with list of files relative to the users files folder
165
+     */
166
+    public function getAllFiles($dir) {
167
+        $result = array();
168
+        $dirList = array($dir);
169
+
170
+        while ($dirList) {
171
+            $dir = array_pop($dirList);
172
+            $content = $this->rootView->getDirectoryContent($dir);
173
+
174
+            foreach ($content as $c) {
175
+                if ($c->getType() === 'dir') {
176
+                    $dirList[] = $c->getPath();
177
+                } else {
178
+                    $result[] =  $c->getPath();
179
+                }
180
+            }
181
+
182
+        }
183
+
184
+        return $result;
185
+    }
186
+
187
+    /**
188
+     * check if it is a file uploaded by the user stored in data/user/files
189
+     * or a metadata file
190
+     *
191
+     * @param string $path relative to the data/ folder
192
+     * @return boolean
193
+     */
194
+    public function isFile($path) {
195
+        $parts = explode('/', Filesystem::normalizePath($path), 4);
196
+        if (isset($parts[2]) && $parts[2] === 'files') {
197
+            return true;
198
+        }
199
+        return false;
200
+    }
201
+
202
+    /**
203
+     * return size of encryption header
204
+     *
205
+     * @return integer
206
+     */
207
+    public function getHeaderSize() {
208
+        return $this->headerSize;
209
+    }
210
+
211
+    /**
212
+     * return size of block read by a PHP stream
213
+     *
214
+     * @return integer
215
+     */
216
+    public function getBlockSize() {
217
+        return $this->blockSize;
218
+    }
219
+
220
+    /**
221
+     * get the owner and the path for the file relative to the owners files folder
222
+     *
223
+     * @param string $path
224
+     * @return array
225
+     * @throws \BadMethodCallException
226
+     */
227
+    public function getUidAndFilename($path) {
228
+
229
+        $parts = explode('/', $path);
230
+        $uid = '';
231
+        if (count($parts) > 2) {
232
+            $uid = $parts[1];
233
+        }
234
+        if (!$this->userManager->userExists($uid)) {
235
+            throw new \BadMethodCallException(
236
+                'path needs to be relative to the system wide data folder and point to a user specific file'
237
+            );
238
+        }
239
+
240
+        $ownerPath = implode('/', array_slice($parts, 2));
241
+
242
+        return array($uid, Filesystem::normalizePath($ownerPath));
243
+
244
+    }
245
+
246
+    /**
247
+     * Remove .path extension from a file path
248
+     * @param string $path Path that may identify a .part file
249
+     * @return string File path without .part extension
250
+     * @note this is needed for reusing keys
251
+     */
252
+    public function stripPartialFileExtension($path) {
253
+        $extension = pathinfo($path, PATHINFO_EXTENSION);
254
+
255
+        if ( $extension === 'part') {
256
+
257
+            $newLength = strlen($path) - 5; // 5 = strlen(".part")
258
+            $fPath = substr($path, 0, $newLength);
259
+
260
+            // if path also contains a transaction id, we remove it too
261
+            $extension = pathinfo($fPath, PATHINFO_EXTENSION);
262
+            if(substr($extension, 0, 12) === 'ocTransferId') { // 12 = strlen("ocTransferId")
263
+                $newLength = strlen($fPath) - strlen($extension) -1;
264
+                $fPath = substr($fPath, 0, $newLength);
265
+            }
266
+            return $fPath;
267
+
268
+        } else {
269
+            return $path;
270
+        }
271
+    }
272
+
273
+    public function getUserWithAccessToMountPoint($users, $groups) {
274
+        $result = array();
275
+        if (in_array('all', $users)) {
276
+            $result = \OCP\User::getUsers();
277
+        } else {
278
+            $result = array_merge($result, $users);
279
+
280
+            $groupManager = \OC::$server->getGroupManager();
281
+            foreach ($groups as $group) {
282
+                $groupObject = $groupManager->get($group);
283
+                if ($groupObject) {
284
+                    $foundUsers = $groupObject->searchUsers('', -1, 0);
285
+                    $userIds = [];
286
+                    foreach ($foundUsers as $user) {
287
+                        $userIds[] = $user->getUID();
288
+                    }
289
+                    $result = array_merge($result, $userIds);
290
+                }
291
+            }
292
+        }
293
+
294
+        return $result;
295
+    }
296
+
297
+    /**
298
+     * check if the file is stored on a system wide mount point
299
+     * @param string $path relative to /data/user with leading '/'
300
+     * @param string $uid
301
+     * @return boolean
302
+     */
303
+    public function isSystemWideMountPoint($path, $uid) {
304
+        if (\OCP\App::isEnabled("files_external")) {
305
+            $mounts = \OC_Mount_Config::getSystemMountPoints();
306
+            foreach ($mounts as $mount) {
307
+                if (strpos($path, '/files/' . $mount['mountpoint']) === 0) {
308
+                    if ($this->isMountPointApplicableToUser($mount, $uid)) {
309
+                        return true;
310
+                    }
311
+                }
312
+            }
313
+        }
314
+        return false;
315
+    }
316
+
317
+    /**
318
+     * check if mount point is applicable to user
319
+     *
320
+     * @param array $mount contains $mount['applicable']['users'], $mount['applicable']['groups']
321
+     * @param string $uid
322
+     * @return boolean
323
+     */
324
+    private function isMountPointApplicableToUser($mount, $uid) {
325
+        $acceptedUids = array('all', $uid);
326
+        // check if mount point is applicable for the user
327
+        $intersection = array_intersect($acceptedUids, $mount['applicable']['users']);
328
+        if (!empty($intersection)) {
329
+            return true;
330
+        }
331
+        // check if mount point is applicable for group where the user is a member
332
+        foreach ($mount['applicable']['groups'] as $gid) {
333
+            if ($this->groupManager->isInGroup($uid, $gid)) {
334
+                return true;
335
+            }
336
+        }
337
+        return false;
338
+    }
339
+
340
+    /**
341
+     * check if it is a path which is excluded by ownCloud from encryption
342
+     *
343
+     * @param string $path
344
+     * @return boolean
345
+     */
346
+    public function isExcluded($path) {
347
+        $normalizedPath = Filesystem::normalizePath($path);
348
+        $root = explode('/', $normalizedPath, 4);
349
+        if (count($root) > 1) {
350
+
351
+            // detect alternative key storage root
352
+            $rootDir = $this->getKeyStorageRoot();
353
+            if ($rootDir !== '' &&
354
+                0 === strpos(
355
+                    Filesystem::normalizePath($path),
356
+                    Filesystem::normalizePath($rootDir)
357
+                )
358
+            ) {
359
+                return true;
360
+            }
361
+
362
+
363
+            //detect system wide folders
364
+            if (in_array($root[1], $this->excludedPaths)) {
365
+                return true;
366
+            }
367
+
368
+            // detect user specific folders
369
+            if ($this->userManager->userExists($root[1])
370
+                && in_array($root[2], $this->excludedPaths)) {
371
+
372
+                return true;
373
+            }
374
+        }
375
+        return false;
376
+    }
377
+
378
+    /**
379
+     * check if recovery key is enabled for user
380
+     *
381
+     * @param string $uid
382
+     * @return boolean
383
+     */
384
+    public function recoveryEnabled($uid) {
385
+        $enabled = $this->config->getUserValue($uid, 'encryption', 'recovery_enabled', '0');
386
+
387
+        return $enabled === '1';
388
+    }
389
+
390
+    /**
391
+     * set new key storage root
392
+     *
393
+     * @param string $root new key store root relative to the data folder
394
+     */
395
+    public function setKeyStorageRoot($root) {
396
+        $this->config->setAppValue('core', 'encryption_key_storage_root', $root);
397
+    }
398
+
399
+    /**
400
+     * get key storage root
401
+     *
402
+     * @return string key storage root
403
+     */
404
+    public function getKeyStorageRoot() {
405
+        return $this->config->getAppValue('core', 'encryption_key_storage_root', '');
406
+    }
407 407
 
408 408
 }
Please login to merge, or discard this patch.