Completed
Pull Request — master (#8789)
by Morris
90:52 queued 74:57
created
apps/files_external/lib/config.php 1 patch
Indentation   +367 added lines, -367 removed lines patch added patch discarded remove patch
@@ -52,371 +52,371 @@
 block discarded – undo
52 52
  * Class to configure mount.json globally and for users
53 53
  */
54 54
 class OC_Mount_Config {
55
-	// TODO: make this class non-static and give it a proper namespace
56
-
57
-	const MOUNT_TYPE_GLOBAL = 'global';
58
-	const MOUNT_TYPE_GROUP = 'group';
59
-	const MOUNT_TYPE_USER = 'user';
60
-	const MOUNT_TYPE_PERSONAL = 'personal';
61
-
62
-	// whether to skip backend test (for unit tests, as this static class is not mockable)
63
-	public static $skipTest = false;
64
-
65
-	/** @var Application */
66
-	public static $app;
67
-
68
-	/**
69
-	 * @param string $class
70
-	 * @param array $definition
71
-	 * @return bool
72
-	 * @deprecated 8.2.0 use \OCA\Files_External\Service\BackendService::registerBackend()
73
-	 */
74
-	public static function registerBackend($class, $definition) {
75
-		$backendService = self::$app->getContainer()->query(BackendService::class);
76
-		$auth = self::$app->getContainer()->query(Builtin::class);
77
-
78
-		$backendService->registerBackend(new LegacyBackend($class, $definition, $auth));
79
-
80
-		return true;
81
-	}
82
-
83
-	/**
84
-	 * Returns the mount points for the given user.
85
-	 * The mount point is relative to the data directory.
86
-	 *
87
-	 * @param string $uid user
88
-	 * @return array of mount point string as key, mountpoint config as value
89
-	 *
90
-	 * @deprecated 8.2.0 use UserGlobalStoragesService::getStorages() and UserStoragesService::getStorages()
91
-	 */
92
-	public static function getAbsoluteMountPoints($uid) {
93
-		$mountPoints = array();
94
-
95
-		$userGlobalStoragesService = self::$app->getContainer()->query(UserGlobalStoragesService::class);
96
-		$userStoragesService = self::$app->getContainer()->query(UserStoragesService::class);
97
-		$user = self::$app->getContainer()->query(IUserManager::class)->get($uid);
98
-
99
-		$userGlobalStoragesService->setUser($user);
100
-		$userStoragesService->setUser($user);
101
-
102
-		foreach ($userGlobalStoragesService->getStorages() as $storage) {
103
-			/** @var \OCA\Files_External\Lib\StorageConfig $storage */
104
-			$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
105
-			$mountEntry = self::prepareMountPointEntry($storage, false);
106
-			foreach ($mountEntry['options'] as &$option) {
107
-				$option = self::setUserVars($uid, $option);
108
-			}
109
-			$mountPoints[$mountPoint] = $mountEntry;
110
-		}
111
-
112
-		foreach ($userStoragesService->getStorages() as $storage) {
113
-			$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
114
-			$mountEntry = self::prepareMountPointEntry($storage, true);
115
-			foreach ($mountEntry['options'] as &$option) {
116
-				$option = self::setUserVars($uid, $option);
117
-			}
118
-			$mountPoints[$mountPoint] = $mountEntry;
119
-		}
120
-
121
-		$userGlobalStoragesService->resetUser();
122
-		$userStoragesService->resetUser();
123
-
124
-		return $mountPoints;
125
-	}
126
-
127
-	/**
128
-	 * Get the system mount points
129
-	 *
130
-	 * @return array
131
-	 *
132
-	 * @deprecated 8.2.0 use GlobalStoragesService::getStorages()
133
-	 */
134
-	public static function getSystemMountPoints() {
135
-		$mountPoints = [];
136
-		$service = self::$app->getContainer()->query(GlobalStoragesService::class);
137
-
138
-		foreach ($service->getStorages() as $storage) {
139
-			$mountPoints[] = self::prepareMountPointEntry($storage, false);
140
-		}
141
-
142
-		return $mountPoints;
143
-	}
144
-
145
-	/**
146
-	 * Get the personal mount points of the current user
147
-	 *
148
-	 * @return array
149
-	 *
150
-	 * @deprecated 8.2.0 use UserStoragesService::getStorages()
151
-	 */
152
-	public static function getPersonalMountPoints() {
153
-		$mountPoints = [];
154
-		$service = self::$app->getContainer()->query(UserStoragesService::class);
155
-
156
-		foreach ($service->getStorages() as $storage) {
157
-			$mountPoints[] = self::prepareMountPointEntry($storage, true);
158
-		}
159
-
160
-		return $mountPoints;
161
-	}
162
-
163
-	/**
164
-	 * Convert a StorageConfig to the legacy mountPoints array format
165
-	 * There's a lot of extra information in here, to satisfy all of the legacy functions
166
-	 *
167
-	 * @param StorageConfig $storage
168
-	 * @param bool $isPersonal
169
-	 * @return array
170
-	 */
171
-	private static function prepareMountPointEntry(StorageConfig $storage, $isPersonal) {
172
-		$mountEntry = [];
173
-
174
-		$mountEntry['mountpoint'] = substr($storage->getMountPoint(), 1); // remove leading slash
175
-		$mountEntry['class'] = $storage->getBackend()->getIdentifier();
176
-		$mountEntry['backend'] = $storage->getBackend()->getText();
177
-		$mountEntry['authMechanism'] = $storage->getAuthMechanism()->getIdentifier();
178
-		$mountEntry['personal'] = $isPersonal;
179
-		$mountEntry['options'] = self::decryptPasswords($storage->getBackendOptions());
180
-		$mountEntry['mountOptions'] = $storage->getMountOptions();
181
-		$mountEntry['priority'] = $storage->getPriority();
182
-		$mountEntry['applicable'] = [
183
-			'groups' => $storage->getApplicableGroups(),
184
-			'users' => $storage->getApplicableUsers(),
185
-		];
186
-		// if mountpoint is applicable to all users the old API expects ['all']
187
-		if (empty($mountEntry['applicable']['groups']) && empty($mountEntry['applicable']['users'])) {
188
-			$mountEntry['applicable']['users'] = ['all'];
189
-		}
190
-
191
-		$mountEntry['id'] = $storage->getId();
192
-
193
-		return $mountEntry;
194
-	}
195
-
196
-	/**
197
-	 * fill in the correct values for $user
198
-	 *
199
-	 * @param string $user user value
200
-	 * @param string|array $input
201
-	 * @return string
202
-	 */
203
-	public static function setUserVars($user, $input) {
204
-		if (is_array($input)) {
205
-			foreach ($input as &$value) {
206
-				if (is_string($value)) {
207
-					$value = str_replace('$user', $user, $value);
208
-				}
209
-			}
210
-		} else {
211
-			if (is_string($input)) {
212
-				$input = str_replace('$user', $user, $input);
213
-			}
214
-		}
215
-		return $input;
216
-	}
217
-
218
-	/**
219
-	 * Test connecting using the given backend configuration
220
-	 *
221
-	 * @param string $class backend class name
222
-	 * @param array $options backend configuration options
223
-	 * @param boolean $isPersonal
224
-	 * @return int see self::STATUS_*
225
-	 * @throws Exception
226
-	 */
227
-	public static function getBackendStatus($class, $options, $isPersonal, $testOnly = true) {
228
-		if (self::$skipTest) {
229
-			return StorageNotAvailableException::STATUS_SUCCESS;
230
-		}
231
-		foreach ($options as &$option) {
232
-			$option = self::setUserVars(OCP\User::getUser(), $option);
233
-		}
234
-		if (class_exists($class)) {
235
-			try {
236
-				/** @var \OC\Files\Storage\Common $storage */
237
-				$storage = new $class($options);
238
-
239
-				try {
240
-					$result = $storage->test($isPersonal, $testOnly);
241
-					$storage->setAvailability($result);
242
-					if ($result) {
243
-						return StorageNotAvailableException::STATUS_SUCCESS;
244
-					}
245
-				} catch (\Exception $e) {
246
-					$storage->setAvailability(false);
247
-					throw $e;
248
-				}
249
-			} catch (Exception $exception) {
250
-				\OC::$server->getLogger()->logException($exception, ['app' => 'files_external']);
251
-				throw $exception;
252
-			}
253
-		}
254
-		return StorageNotAvailableException::STATUS_ERROR;
255
-	}
256
-
257
-	/**
258
-	 * Read the mount points in the config file into an array
259
-	 *
260
-	 * @param string|null $user If not null, personal for $user, otherwise system
261
-	 * @return array
262
-	 */
263
-	public static function readData($user = null) {
264
-		if (isset($user)) {
265
-			$jsonFile = \OC::$server->getUserManager()->get($user)->getHome() . '/mount.json';
266
-		} else {
267
-			$config = \OC::$server->getConfig();
268
-			$datadir = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/');
269
-			$jsonFile = $config->getSystemValue('mount_file', $datadir . '/mount.json');
270
-		}
271
-		if (is_file($jsonFile)) {
272
-			$mountPoints = json_decode(file_get_contents($jsonFile), true);
273
-			if (is_array($mountPoints)) {
274
-				return $mountPoints;
275
-			}
276
-		}
277
-		return array();
278
-	}
279
-
280
-	/**
281
-	 * Get backend dependency message
282
-	 * TODO: move into AppFramework along with templates
283
-	 *
284
-	 * @param Backend[] $backends
285
-	 * @return string
286
-	 */
287
-	public static function dependencyMessage($backends) {
288
-		$l = \OC::$server->getL10N('files_external');
289
-		$message = '';
290
-		$dependencyGroups = [];
291
-
292
-		foreach ($backends as $backend) {
293
-			foreach ($backend->checkDependencies() as $dependency) {
294
-				if ($message = $dependency->getMessage()) {
295
-					$message .= '<p>' . $message . '</p>';
296
-				} else {
297
-					$dependencyGroups[$dependency->getDependency()][] = $backend;
298
-				}
299
-			}
300
-		}
301
-
302
-		foreach ($dependencyGroups as $module => $dependants) {
303
-			$backends = implode(', ', array_map(function($backend) {
304
-				return '"' . $backend->getText() . '"';
305
-			}, $dependants));
306
-			$message .= '<p>' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends) . '</p>';
307
-		}
308
-
309
-		return $message;
310
-	}
311
-
312
-	/**
313
-	 * Returns a dependency missing message
314
-	 *
315
-	 * @param \OCP\IL10N $l
316
-	 * @param string $module
317
-	 * @param string $backend
318
-	 * @return string
319
-	 */
320
-	private static function getSingleDependencyMessage(\OCP\IL10N $l, $module, $backend) {
321
-		switch (strtolower($module)) {
322
-			case 'curl':
323
-				return (string)$l->t('The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]);
324
-			case 'ftp':
325
-				return (string)$l->t('The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]);
326
-			default:
327
-				return (string)$l->t('"%s" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$module, $backend]);
328
-		}
329
-	}
330
-
331
-	/**
332
-	 * Encrypt passwords in the given config options
333
-	 *
334
-	 * @param array $options mount options
335
-	 * @return array updated options
336
-	 */
337
-	public static function encryptPasswords($options) {
338
-		if (isset($options['password'])) {
339
-			$options['password_encrypted'] = self::encryptPassword($options['password']);
340
-			// do not unset the password, we want to keep the keys order
341
-			// on load... because that's how the UI currently works
342
-			$options['password'] = '';
343
-		}
344
-		return $options;
345
-	}
346
-
347
-	/**
348
-	 * Decrypt passwords in the given config options
349
-	 *
350
-	 * @param array $options mount options
351
-	 * @return array updated options
352
-	 */
353
-	public static function decryptPasswords($options) {
354
-		// note: legacy options might still have the unencrypted password in the "password" field
355
-		if (isset($options['password_encrypted'])) {
356
-			$options['password'] = self::decryptPassword($options['password_encrypted']);
357
-			unset($options['password_encrypted']);
358
-		}
359
-		return $options;
360
-	}
361
-
362
-	/**
363
-	 * Encrypt a single password
364
-	 *
365
-	 * @param string $password plain text password
366
-	 * @return string encrypted password
367
-	 */
368
-	private static function encryptPassword($password) {
369
-		$cipher = self::getCipher();
370
-		$iv = \OC::$server->getSecureRandom()->generate(16);
371
-		$cipher->setIV($iv);
372
-		return base64_encode($iv . $cipher->encrypt($password));
373
-	}
374
-
375
-	/**
376
-	 * Decrypts a single password
377
-	 *
378
-	 * @param string $encryptedPassword encrypted password
379
-	 * @return string plain text password
380
-	 */
381
-	private static function decryptPassword($encryptedPassword) {
382
-		$cipher = self::getCipher();
383
-		$binaryPassword = base64_decode($encryptedPassword);
384
-		$iv = substr($binaryPassword, 0, 16);
385
-		$cipher->setIV($iv);
386
-		$binaryPassword = substr($binaryPassword, 16);
387
-		return $cipher->decrypt($binaryPassword);
388
-	}
389
-
390
-	/**
391
-	 * Returns the encryption cipher
392
-	 *
393
-	 * @return AES
394
-	 */
395
-	private static function getCipher() {
396
-		$cipher = new AES(AES::MODE_CBC);
397
-		$cipher->setKey(\OC::$server->getConfig()->getSystemValue('passwordsalt', null));
398
-		return $cipher;
399
-	}
400
-
401
-	/**
402
-	 * Computes a hash based on the given configuration.
403
-	 * This is mostly used to find out whether configurations
404
-	 * are the same.
405
-	 *
406
-	 * @param array $config
407
-	 * @return string
408
-	 */
409
-	public static function makeConfigHash($config) {
410
-		$data = json_encode(
411
-			array(
412
-				'c' => $config['backend'],
413
-				'a' => $config['authMechanism'],
414
-				'm' => $config['mountpoint'],
415
-				'o' => $config['options'],
416
-				'p' => isset($config['priority']) ? $config['priority'] : -1,
417
-				'mo' => isset($config['mountOptions']) ? $config['mountOptions'] : [],
418
-			)
419
-		);
420
-		return hash('md5', $data);
421
-	}
55
+    // TODO: make this class non-static and give it a proper namespace
56
+
57
+    const MOUNT_TYPE_GLOBAL = 'global';
58
+    const MOUNT_TYPE_GROUP = 'group';
59
+    const MOUNT_TYPE_USER = 'user';
60
+    const MOUNT_TYPE_PERSONAL = 'personal';
61
+
62
+    // whether to skip backend test (for unit tests, as this static class is not mockable)
63
+    public static $skipTest = false;
64
+
65
+    /** @var Application */
66
+    public static $app;
67
+
68
+    /**
69
+     * @param string $class
70
+     * @param array $definition
71
+     * @return bool
72
+     * @deprecated 8.2.0 use \OCA\Files_External\Service\BackendService::registerBackend()
73
+     */
74
+    public static function registerBackend($class, $definition) {
75
+        $backendService = self::$app->getContainer()->query(BackendService::class);
76
+        $auth = self::$app->getContainer()->query(Builtin::class);
77
+
78
+        $backendService->registerBackend(new LegacyBackend($class, $definition, $auth));
79
+
80
+        return true;
81
+    }
82
+
83
+    /**
84
+     * Returns the mount points for the given user.
85
+     * The mount point is relative to the data directory.
86
+     *
87
+     * @param string $uid user
88
+     * @return array of mount point string as key, mountpoint config as value
89
+     *
90
+     * @deprecated 8.2.0 use UserGlobalStoragesService::getStorages() and UserStoragesService::getStorages()
91
+     */
92
+    public static function getAbsoluteMountPoints($uid) {
93
+        $mountPoints = array();
94
+
95
+        $userGlobalStoragesService = self::$app->getContainer()->query(UserGlobalStoragesService::class);
96
+        $userStoragesService = self::$app->getContainer()->query(UserStoragesService::class);
97
+        $user = self::$app->getContainer()->query(IUserManager::class)->get($uid);
98
+
99
+        $userGlobalStoragesService->setUser($user);
100
+        $userStoragesService->setUser($user);
101
+
102
+        foreach ($userGlobalStoragesService->getStorages() as $storage) {
103
+            /** @var \OCA\Files_External\Lib\StorageConfig $storage */
104
+            $mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
105
+            $mountEntry = self::prepareMountPointEntry($storage, false);
106
+            foreach ($mountEntry['options'] as &$option) {
107
+                $option = self::setUserVars($uid, $option);
108
+            }
109
+            $mountPoints[$mountPoint] = $mountEntry;
110
+        }
111
+
112
+        foreach ($userStoragesService->getStorages() as $storage) {
113
+            $mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
114
+            $mountEntry = self::prepareMountPointEntry($storage, true);
115
+            foreach ($mountEntry['options'] as &$option) {
116
+                $option = self::setUserVars($uid, $option);
117
+            }
118
+            $mountPoints[$mountPoint] = $mountEntry;
119
+        }
120
+
121
+        $userGlobalStoragesService->resetUser();
122
+        $userStoragesService->resetUser();
123
+
124
+        return $mountPoints;
125
+    }
126
+
127
+    /**
128
+     * Get the system mount points
129
+     *
130
+     * @return array
131
+     *
132
+     * @deprecated 8.2.0 use GlobalStoragesService::getStorages()
133
+     */
134
+    public static function getSystemMountPoints() {
135
+        $mountPoints = [];
136
+        $service = self::$app->getContainer()->query(GlobalStoragesService::class);
137
+
138
+        foreach ($service->getStorages() as $storage) {
139
+            $mountPoints[] = self::prepareMountPointEntry($storage, false);
140
+        }
141
+
142
+        return $mountPoints;
143
+    }
144
+
145
+    /**
146
+     * Get the personal mount points of the current user
147
+     *
148
+     * @return array
149
+     *
150
+     * @deprecated 8.2.0 use UserStoragesService::getStorages()
151
+     */
152
+    public static function getPersonalMountPoints() {
153
+        $mountPoints = [];
154
+        $service = self::$app->getContainer()->query(UserStoragesService::class);
155
+
156
+        foreach ($service->getStorages() as $storage) {
157
+            $mountPoints[] = self::prepareMountPointEntry($storage, true);
158
+        }
159
+
160
+        return $mountPoints;
161
+    }
162
+
163
+    /**
164
+     * Convert a StorageConfig to the legacy mountPoints array format
165
+     * There's a lot of extra information in here, to satisfy all of the legacy functions
166
+     *
167
+     * @param StorageConfig $storage
168
+     * @param bool $isPersonal
169
+     * @return array
170
+     */
171
+    private static function prepareMountPointEntry(StorageConfig $storage, $isPersonal) {
172
+        $mountEntry = [];
173
+
174
+        $mountEntry['mountpoint'] = substr($storage->getMountPoint(), 1); // remove leading slash
175
+        $mountEntry['class'] = $storage->getBackend()->getIdentifier();
176
+        $mountEntry['backend'] = $storage->getBackend()->getText();
177
+        $mountEntry['authMechanism'] = $storage->getAuthMechanism()->getIdentifier();
178
+        $mountEntry['personal'] = $isPersonal;
179
+        $mountEntry['options'] = self::decryptPasswords($storage->getBackendOptions());
180
+        $mountEntry['mountOptions'] = $storage->getMountOptions();
181
+        $mountEntry['priority'] = $storage->getPriority();
182
+        $mountEntry['applicable'] = [
183
+            'groups' => $storage->getApplicableGroups(),
184
+            'users' => $storage->getApplicableUsers(),
185
+        ];
186
+        // if mountpoint is applicable to all users the old API expects ['all']
187
+        if (empty($mountEntry['applicable']['groups']) && empty($mountEntry['applicable']['users'])) {
188
+            $mountEntry['applicable']['users'] = ['all'];
189
+        }
190
+
191
+        $mountEntry['id'] = $storage->getId();
192
+
193
+        return $mountEntry;
194
+    }
195
+
196
+    /**
197
+     * fill in the correct values for $user
198
+     *
199
+     * @param string $user user value
200
+     * @param string|array $input
201
+     * @return string
202
+     */
203
+    public static function setUserVars($user, $input) {
204
+        if (is_array($input)) {
205
+            foreach ($input as &$value) {
206
+                if (is_string($value)) {
207
+                    $value = str_replace('$user', $user, $value);
208
+                }
209
+            }
210
+        } else {
211
+            if (is_string($input)) {
212
+                $input = str_replace('$user', $user, $input);
213
+            }
214
+        }
215
+        return $input;
216
+    }
217
+
218
+    /**
219
+     * Test connecting using the given backend configuration
220
+     *
221
+     * @param string $class backend class name
222
+     * @param array $options backend configuration options
223
+     * @param boolean $isPersonal
224
+     * @return int see self::STATUS_*
225
+     * @throws Exception
226
+     */
227
+    public static function getBackendStatus($class, $options, $isPersonal, $testOnly = true) {
228
+        if (self::$skipTest) {
229
+            return StorageNotAvailableException::STATUS_SUCCESS;
230
+        }
231
+        foreach ($options as &$option) {
232
+            $option = self::setUserVars(OCP\User::getUser(), $option);
233
+        }
234
+        if (class_exists($class)) {
235
+            try {
236
+                /** @var \OC\Files\Storage\Common $storage */
237
+                $storage = new $class($options);
238
+
239
+                try {
240
+                    $result = $storage->test($isPersonal, $testOnly);
241
+                    $storage->setAvailability($result);
242
+                    if ($result) {
243
+                        return StorageNotAvailableException::STATUS_SUCCESS;
244
+                    }
245
+                } catch (\Exception $e) {
246
+                    $storage->setAvailability(false);
247
+                    throw $e;
248
+                }
249
+            } catch (Exception $exception) {
250
+                \OC::$server->getLogger()->logException($exception, ['app' => 'files_external']);
251
+                throw $exception;
252
+            }
253
+        }
254
+        return StorageNotAvailableException::STATUS_ERROR;
255
+    }
256
+
257
+    /**
258
+     * Read the mount points in the config file into an array
259
+     *
260
+     * @param string|null $user If not null, personal for $user, otherwise system
261
+     * @return array
262
+     */
263
+    public static function readData($user = null) {
264
+        if (isset($user)) {
265
+            $jsonFile = \OC::$server->getUserManager()->get($user)->getHome() . '/mount.json';
266
+        } else {
267
+            $config = \OC::$server->getConfig();
268
+            $datadir = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/');
269
+            $jsonFile = $config->getSystemValue('mount_file', $datadir . '/mount.json');
270
+        }
271
+        if (is_file($jsonFile)) {
272
+            $mountPoints = json_decode(file_get_contents($jsonFile), true);
273
+            if (is_array($mountPoints)) {
274
+                return $mountPoints;
275
+            }
276
+        }
277
+        return array();
278
+    }
279
+
280
+    /**
281
+     * Get backend dependency message
282
+     * TODO: move into AppFramework along with templates
283
+     *
284
+     * @param Backend[] $backends
285
+     * @return string
286
+     */
287
+    public static function dependencyMessage($backends) {
288
+        $l = \OC::$server->getL10N('files_external');
289
+        $message = '';
290
+        $dependencyGroups = [];
291
+
292
+        foreach ($backends as $backend) {
293
+            foreach ($backend->checkDependencies() as $dependency) {
294
+                if ($message = $dependency->getMessage()) {
295
+                    $message .= '<p>' . $message . '</p>';
296
+                } else {
297
+                    $dependencyGroups[$dependency->getDependency()][] = $backend;
298
+                }
299
+            }
300
+        }
301
+
302
+        foreach ($dependencyGroups as $module => $dependants) {
303
+            $backends = implode(', ', array_map(function($backend) {
304
+                return '"' . $backend->getText() . '"';
305
+            }, $dependants));
306
+            $message .= '<p>' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends) . '</p>';
307
+        }
308
+
309
+        return $message;
310
+    }
311
+
312
+    /**
313
+     * Returns a dependency missing message
314
+     *
315
+     * @param \OCP\IL10N $l
316
+     * @param string $module
317
+     * @param string $backend
318
+     * @return string
319
+     */
320
+    private static function getSingleDependencyMessage(\OCP\IL10N $l, $module, $backend) {
321
+        switch (strtolower($module)) {
322
+            case 'curl':
323
+                return (string)$l->t('The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]);
324
+            case 'ftp':
325
+                return (string)$l->t('The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]);
326
+            default:
327
+                return (string)$l->t('"%s" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$module, $backend]);
328
+        }
329
+    }
330
+
331
+    /**
332
+     * Encrypt passwords in the given config options
333
+     *
334
+     * @param array $options mount options
335
+     * @return array updated options
336
+     */
337
+    public static function encryptPasswords($options) {
338
+        if (isset($options['password'])) {
339
+            $options['password_encrypted'] = self::encryptPassword($options['password']);
340
+            // do not unset the password, we want to keep the keys order
341
+            // on load... because that's how the UI currently works
342
+            $options['password'] = '';
343
+        }
344
+        return $options;
345
+    }
346
+
347
+    /**
348
+     * Decrypt passwords in the given config options
349
+     *
350
+     * @param array $options mount options
351
+     * @return array updated options
352
+     */
353
+    public static function decryptPasswords($options) {
354
+        // note: legacy options might still have the unencrypted password in the "password" field
355
+        if (isset($options['password_encrypted'])) {
356
+            $options['password'] = self::decryptPassword($options['password_encrypted']);
357
+            unset($options['password_encrypted']);
358
+        }
359
+        return $options;
360
+    }
361
+
362
+    /**
363
+     * Encrypt a single password
364
+     *
365
+     * @param string $password plain text password
366
+     * @return string encrypted password
367
+     */
368
+    private static function encryptPassword($password) {
369
+        $cipher = self::getCipher();
370
+        $iv = \OC::$server->getSecureRandom()->generate(16);
371
+        $cipher->setIV($iv);
372
+        return base64_encode($iv . $cipher->encrypt($password));
373
+    }
374
+
375
+    /**
376
+     * Decrypts a single password
377
+     *
378
+     * @param string $encryptedPassword encrypted password
379
+     * @return string plain text password
380
+     */
381
+    private static function decryptPassword($encryptedPassword) {
382
+        $cipher = self::getCipher();
383
+        $binaryPassword = base64_decode($encryptedPassword);
384
+        $iv = substr($binaryPassword, 0, 16);
385
+        $cipher->setIV($iv);
386
+        $binaryPassword = substr($binaryPassword, 16);
387
+        return $cipher->decrypt($binaryPassword);
388
+    }
389
+
390
+    /**
391
+     * Returns the encryption cipher
392
+     *
393
+     * @return AES
394
+     */
395
+    private static function getCipher() {
396
+        $cipher = new AES(AES::MODE_CBC);
397
+        $cipher->setKey(\OC::$server->getConfig()->getSystemValue('passwordsalt', null));
398
+        return $cipher;
399
+    }
400
+
401
+    /**
402
+     * Computes a hash based on the given configuration.
403
+     * This is mostly used to find out whether configurations
404
+     * are the same.
405
+     *
406
+     * @param array $config
407
+     * @return string
408
+     */
409
+    public static function makeConfigHash($config) {
410
+        $data = json_encode(
411
+            array(
412
+                'c' => $config['backend'],
413
+                'a' => $config['authMechanism'],
414
+                'm' => $config['mountpoint'],
415
+                'o' => $config['options'],
416
+                'p' => isset($config['priority']) ? $config['priority'] : -1,
417
+                'mo' => isset($config['mountOptions']) ? $config['mountOptions'] : [],
418
+            )
419
+        );
420
+        return hash('md5', $data);
421
+    }
422 422
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/AmazonS3.php 2 patches
Indentation   +556 added lines, -556 removed lines patch added patch discarded remove patch
@@ -46,561 +46,561 @@
 block discarded – undo
46 46
 use OCP\Constants;
47 47
 
48 48
 class AmazonS3 extends \OC\Files\Storage\Common {
49
-	use S3ConnectionTrait;
50
-	use S3ObjectTrait;
51
-
52
-	public function needsPartFile() {
53
-		return false;
54
-	}
55
-
56
-	/**
57
-	 * @var int in seconds
58
-	 */
59
-	private $rescanDelay = 10;
60
-
61
-	/** @var CappedMemoryCache|Result[] */
62
-	private $objectCache;
63
-
64
-	public function __construct($parameters) {
65
-		parent::__construct($parameters);
66
-		$this->parseParams($parameters);
67
-		$this->objectCache = new CappedMemoryCache();
68
-	}
69
-
70
-	/**
71
-	 * @param string $path
72
-	 * @return string correctly encoded path
73
-	 */
74
-	private function normalizePath($path) {
75
-		$path = trim($path, '/');
76
-
77
-		if (!$path) {
78
-			$path = '.';
79
-		}
80
-
81
-		return $path;
82
-	}
83
-
84
-	private function isRoot($path) {
85
-		return $path === '.';
86
-	}
87
-
88
-	private function cleanKey($path) {
89
-		if ($this->isRoot($path)) {
90
-			return '/';
91
-		}
92
-		return $path;
93
-	}
94
-
95
-	private function clearCache() {
96
-		$this->objectCache = new CappedMemoryCache();
97
-	}
98
-
99
-	private function invalidateCache($key) {
100
-		unset($this->objectCache[$key]);
101
-		$keys = array_keys($this->objectCache->getData());
102
-		$keyLength = strlen($key);
103
-		foreach ($keys as $existingKey) {
104
-			if (substr($existingKey, 0, $keyLength) === $key) {
105
-				unset($this->objectCache[$existingKey]);
106
-			}
107
-		}
108
-	}
109
-
110
-	/**
111
-	 * @param $key
112
-	 * @return Result|boolean
113
-	 */
114
-	private function headObject($key) {
115
-		if (!isset($this->objectCache[$key])) {
116
-			try {
117
-				$this->objectCache[$key] = $this->getConnection()->headObject(array(
118
-					'Bucket' => $this->bucket,
119
-					'Key' => $key
120
-				));
121
-			} catch (S3Exception $e) {
122
-				if ($e->getStatusCode() >= 500) {
123
-					throw $e;
124
-				}
125
-				$this->objectCache[$key] = false;
126
-			}
127
-		}
128
-
129
-		return $this->objectCache[$key];
130
-	}
131
-
132
-	/**
133
-	 * Updates old storage ids (v0.2.1 and older) that are based on key and secret to new ones based on the bucket name.
134
-	 * TODO Do this in an update.php. requires iterating over all users and loading the mount.json from their home
135
-	 *
136
-	 * @param array $params
137
-	 */
138
-	public function updateLegacyId(array $params) {
139
-		$oldId = 'amazon::' . $params['key'] . md5($params['secret']);
140
-
141
-		// find by old id or bucket
142
-		$stmt = \OC::$server->getDatabaseConnection()->prepare(
143
-			'SELECT `numeric_id`, `id` FROM `*PREFIX*storages` WHERE `id` IN (?, ?)'
144
-		);
145
-		$stmt->execute(array($oldId, $this->id));
146
-		while ($row = $stmt->fetch()) {
147
-			$storages[$row['id']] = $row['numeric_id'];
148
-		}
149
-
150
-		if (isset($storages[$this->id]) && isset($storages[$oldId])) {
151
-			// if both ids exist, delete the old storage and corresponding filecache entries
152
-			\OC\Files\Cache\Storage::remove($oldId);
153
-		} else if (isset($storages[$oldId])) {
154
-			// if only the old id exists do an update
155
-			$stmt = \OC::$server->getDatabaseConnection()->prepare(
156
-				'UPDATE `*PREFIX*storages` SET `id` = ? WHERE `id` = ?'
157
-			);
158
-			$stmt->execute(array($this->id, $oldId));
159
-		}
160
-		// only the bucket based id may exist, do nothing
161
-	}
162
-
163
-	/**
164
-	 * Remove a file or folder
165
-	 *
166
-	 * @param string $path
167
-	 * @return bool
168
-	 */
169
-	protected function remove($path) {
170
-		// remember fileType to reduce http calls
171
-		$fileType = $this->filetype($path);
172
-		if ($fileType === 'dir') {
173
-			return $this->rmdir($path);
174
-		} else if ($fileType === 'file') {
175
-			return $this->unlink($path);
176
-		} else {
177
-			return false;
178
-		}
179
-	}
180
-
181
-	public function mkdir($path) {
182
-		$path = $this->normalizePath($path);
183
-
184
-		if ($this->is_dir($path)) {
185
-			return false;
186
-		}
187
-
188
-		try {
189
-			$this->getConnection()->putObject(array(
190
-				'Bucket' => $this->bucket,
191
-				'Key' => $path . '/',
192
-				'Body' => '',
193
-				'ContentType' => 'httpd/unix-directory'
194
-			));
195
-			$this->testTimeout();
196
-		} catch (S3Exception $e) {
197
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
198
-			return false;
199
-		}
200
-
201
-		$this->invalidateCache($path);
202
-
203
-		return true;
204
-	}
205
-
206
-	public function file_exists($path) {
207
-		return $this->filetype($path) !== false;
208
-	}
209
-
210
-
211
-	public function rmdir($path) {
212
-		$path = $this->normalizePath($path);
213
-
214
-		if ($this->isRoot($path)) {
215
-			return $this->clearBucket();
216
-		}
217
-
218
-		if (!$this->file_exists($path)) {
219
-			return false;
220
-		}
221
-
222
-		$this->invalidateCache($path);
223
-		return $this->batchDelete($path);
224
-	}
225
-
226
-	protected function clearBucket() {
227
-		$this->clearCache();
228
-		try {
229
-			$this->getConnection()->clearBucket($this->bucket);
230
-			return true;
231
-			// clearBucket() is not working with Ceph, so if it fails we try the slower approach
232
-		} catch (\Exception $e) {
233
-			return $this->batchDelete();
234
-		}
235
-	}
236
-
237
-	private function batchDelete($path = null) {
238
-		$params = array(
239
-			'Bucket' => $this->bucket
240
-		);
241
-		if ($path !== null) {
242
-			$params['Prefix'] = $path . '/';
243
-		}
244
-		try {
245
-			$connection = $this->getConnection();
246
-			// Since there are no real directories on S3, we need
247
-			// to delete all objects prefixed with the path.
248
-			do {
249
-				// instead of the iterator, manually loop over the list ...
250
-				$objects = $connection->listObjects($params);
251
-				// ... so we can delete the files in batches
252
-				if (isset($objects['Contents'])) {
253
-					$connection->deleteObjects([
254
-						'Bucket' => $this->bucket,
255
-						'Delete' => [
256
-							'Objects' => $objects['Contents']
257
-						]
258
-					]);
259
-					$this->testTimeout();
260
-				}
261
-				// we reached the end when the list is no longer truncated
262
-			} while ($objects['IsTruncated']);
263
-		} catch (S3Exception $e) {
264
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
265
-			return false;
266
-		}
267
-		return true;
268
-	}
269
-
270
-	public function opendir($path) {
271
-		$path = $this->normalizePath($path);
272
-
273
-		if ($this->isRoot($path)) {
274
-			$path = '';
275
-		} else {
276
-			$path .= '/';
277
-		}
278
-
279
-		try {
280
-			$files = array();
281
-			$results = $this->getConnection()->getPaginator('ListObjects', [
282
-				'Bucket' => $this->bucket,
283
-				'Delimiter' => '/',
284
-				'Prefix' => $path,
285
-			]);
286
-
287
-			foreach ($results as $result) {
288
-				// sub folders
289
-				if (is_array($result['CommonPrefixes'])) {
290
-					foreach ($result['CommonPrefixes'] as $prefix) {
291
-						$files[] = substr(trim($prefix['Prefix'], '/'), strlen($path));
292
-					}
293
-				}
294
-				foreach ($result['Contents'] as $object) {
295
-					if (isset($object['Key']) && $object['Key'] === $path) {
296
-						// it's the directory itself, skip
297
-						continue;
298
-					}
299
-					$file = basename(
300
-						isset($object['Key']) ? $object['Key'] : $object['Prefix']
301
-					);
302
-					$files[] = $file;
303
-				}
304
-			}
305
-
306
-			return IteratorDirectory::wrap($files);
307
-		} catch (S3Exception $e) {
308
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
309
-			return false;
310
-		}
311
-	}
312
-
313
-	public function stat($path) {
314
-		$path = $this->normalizePath($path);
315
-
316
-		try {
317
-			$stat = array();
318
-			if ($this->is_dir($path)) {
319
-				//folders don't really exist
320
-				$stat['size'] = -1; //unknown
321
-				$stat['mtime'] = time() - $this->rescanDelay * 1000;
322
-			} else {
323
-				$result = $this->headObject($path);
324
-
325
-				$stat['size'] = $result['ContentLength'] ? $result['ContentLength'] : 0;
326
-				if (isset($result['Metadata']['lastmodified'])) {
327
-					$stat['mtime'] = strtotime($result['Metadata']['lastmodified']);
328
-				} else {
329
-					$stat['mtime'] = strtotime($result['LastModified']);
330
-				}
331
-			}
332
-			$stat['atime'] = time();
333
-
334
-			return $stat;
335
-		} catch (S3Exception $e) {
336
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
337
-			return false;
338
-		}
339
-	}
340
-
341
-	public function is_dir($path) {
342
-		$path = $this->normalizePath($path);
343
-		try {
344
-			return $this->isRoot($path) || $this->headObject($path . '/');
345
-		} catch (S3Exception $e) {
346
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
347
-			return false;
348
-		}
349
-	}
350
-
351
-	public function filetype($path) {
352
-		$path = $this->normalizePath($path);
353
-
354
-		if ($this->isRoot($path)) {
355
-			return 'dir';
356
-		}
357
-
358
-		try {
359
-			if ($this->headObject($path)) {
360
-				return 'file';
361
-			}
362
-			if ($this->headObject($path . '/')) {
363
-				return 'dir';
364
-			}
365
-		} catch (S3Exception $e) {
366
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
367
-			return false;
368
-		}
369
-
370
-		return false;
371
-	}
372
-
373
-	public function getPermissions($path) {
374
-		$type = $this->filetype($path);
375
-		if (!$type) {
376
-			return 0;
377
-		}
378
-		return $type === 'dir' ? Constants::PERMISSION_ALL : Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
379
-	}
380
-
381
-	public function unlink($path) {
382
-		$path = $this->normalizePath($path);
383
-
384
-		if ($this->is_dir($path)) {
385
-			return $this->rmdir($path);
386
-		}
387
-
388
-		try {
389
-			$this->deleteObject($path);
390
-			$this->invalidateCache($path);
391
-		} catch (S3Exception $e) {
392
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
393
-			return false;
394
-		}
395
-
396
-		return true;
397
-	}
398
-
399
-	public function fopen($path, $mode) {
400
-		$path = $this->normalizePath($path);
401
-
402
-		switch ($mode) {
403
-			case 'r':
404
-			case 'rb':
405
-				try {
406
-					return $this->readObject($path);
407
-				} catch (S3Exception $e) {
408
-					\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
409
-					return false;
410
-				}
411
-			case 'w':
412
-			case 'wb':
413
-				$tmpFile = \OCP\Files::tmpFile();
414
-
415
-				$handle = fopen($tmpFile, 'w');
416
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
417
-					$this->writeBack($tmpFile, $path);
418
-				});
419
-			case 'a':
420
-			case 'ab':
421
-			case 'r+':
422
-			case 'w+':
423
-			case 'wb+':
424
-			case 'a+':
425
-			case 'x':
426
-			case 'x+':
427
-			case 'c':
428
-			case 'c+':
429
-				if (strrpos($path, '.') !== false) {
430
-					$ext = substr($path, strrpos($path, '.'));
431
-				} else {
432
-					$ext = '';
433
-				}
434
-				$tmpFile = \OCP\Files::tmpFile($ext);
435
-				if ($this->file_exists($path)) {
436
-					$source = $this->readObject($path);
437
-					file_put_contents($tmpFile, $source);
438
-				}
439
-
440
-				$handle = fopen($tmpFile, $mode);
441
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
442
-					$this->writeBack($tmpFile, $path);
443
-				});
444
-		}
445
-		return false;
446
-	}
447
-
448
-	public function touch($path, $mtime = null) {
449
-		$path = $this->normalizePath($path);
450
-
451
-		$metadata = array();
452
-		if (is_null($mtime)) {
453
-			$mtime = time();
454
-		}
455
-		$metadata = [
456
-			'lastmodified' => gmdate(\DateTime::RFC1123, $mtime)
457
-		];
458
-
459
-		$fileType = $this->filetype($path);
460
-		try {
461
-			if ($fileType !== false) {
462
-				if ($fileType === 'dir' && !$this->isRoot($path)) {
463
-					$path .= '/';
464
-				}
465
-				$this->getConnection()->copyObject([
466
-					'Bucket' => $this->bucket,
467
-					'Key' => $this->cleanKey($path),
468
-					'Metadata' => $metadata,
469
-					'CopySource' => $this->bucket . '/' . $path,
470
-					'MetadataDirective' => 'REPLACE',
471
-				]);
472
-				$this->testTimeout();
473
-			} else {
474
-				$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
475
-				$this->getConnection()->putObject([
476
-					'Bucket' => $this->bucket,
477
-					'Key' => $this->cleanKey($path),
478
-					'Metadata' => $metadata,
479
-					'Body' => '',
480
-					'ContentType' => $mimeType,
481
-					'MetadataDirective' => 'REPLACE',
482
-				]);
483
-				$this->testTimeout();
484
-			}
485
-		} catch (S3Exception $e) {
486
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
487
-			return false;
488
-		}
489
-
490
-		$this->invalidateCache($path);
491
-		return true;
492
-	}
493
-
494
-	public function copy($path1, $path2) {
495
-		$path1 = $this->normalizePath($path1);
496
-		$path2 = $this->normalizePath($path2);
497
-
498
-		if ($this->is_file($path1)) {
499
-			try {
500
-				$this->getConnection()->copyObject(array(
501
-					'Bucket' => $this->bucket,
502
-					'Key' => $this->cleanKey($path2),
503
-					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
504
-				));
505
-				$this->testTimeout();
506
-			} catch (S3Exception $e) {
507
-				\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
508
-				return false;
509
-			}
510
-		} else {
511
-			$this->remove($path2);
512
-
513
-			try {
514
-				$this->getConnection()->copyObject(array(
515
-					'Bucket' => $this->bucket,
516
-					'Key' => $path2 . '/',
517
-					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
518
-				));
519
-				$this->testTimeout();
520
-			} catch (S3Exception $e) {
521
-				\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
522
-				return false;
523
-			}
524
-
525
-			$dh = $this->opendir($path1);
526
-			if (is_resource($dh)) {
527
-				while (($file = readdir($dh)) !== false) {
528
-					if (\OC\Files\Filesystem::isIgnoredDir($file)) {
529
-						continue;
530
-					}
531
-
532
-					$source = $path1 . '/' . $file;
533
-					$target = $path2 . '/' . $file;
534
-					$this->copy($source, $target);
535
-				}
536
-			}
537
-		}
538
-
539
-		$this->invalidateCache($path2);
540
-
541
-		return true;
542
-	}
543
-
544
-	public function rename($path1, $path2) {
545
-		$path1 = $this->normalizePath($path1);
546
-		$path2 = $this->normalizePath($path2);
547
-
548
-		if ($this->is_file($path1)) {
549
-
550
-			if ($this->copy($path1, $path2) === false) {
551
-				return false;
552
-			}
553
-
554
-			if ($this->unlink($path1) === false) {
555
-				$this->unlink($path2);
556
-				return false;
557
-			}
558
-		} else {
559
-
560
-			if ($this->copy($path1, $path2) === false) {
561
-				return false;
562
-			}
563
-
564
-			if ($this->rmdir($path1) === false) {
565
-				$this->rmdir($path2);
566
-				return false;
567
-			}
568
-		}
569
-
570
-		return true;
571
-	}
572
-
573
-	public function test() {
574
-		$this->getConnection()->headBucket([
575
-			'Bucket' => $this->bucket
576
-		]);
577
-		return true;
578
-	}
579
-
580
-	public function getId() {
581
-		return $this->id;
582
-	}
583
-
584
-	public function writeBack($tmpFile, $path) {
585
-		try {
586
-			$source = fopen($tmpFile, 'r');
587
-			$this->writeObject($path, $source);
588
-			$this->invalidateCache($path);
589
-			fclose($source);
590
-
591
-			unlink($tmpFile);
592
-			return true;
593
-		} catch (S3Exception $e) {
594
-			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
595
-			return false;
596
-		}
597
-	}
598
-
599
-	/**
600
-	 * check if curl is installed
601
-	 */
602
-	public static function checkDependencies() {
603
-		return true;
604
-	}
49
+    use S3ConnectionTrait;
50
+    use S3ObjectTrait;
51
+
52
+    public function needsPartFile() {
53
+        return false;
54
+    }
55
+
56
+    /**
57
+     * @var int in seconds
58
+     */
59
+    private $rescanDelay = 10;
60
+
61
+    /** @var CappedMemoryCache|Result[] */
62
+    private $objectCache;
63
+
64
+    public function __construct($parameters) {
65
+        parent::__construct($parameters);
66
+        $this->parseParams($parameters);
67
+        $this->objectCache = new CappedMemoryCache();
68
+    }
69
+
70
+    /**
71
+     * @param string $path
72
+     * @return string correctly encoded path
73
+     */
74
+    private function normalizePath($path) {
75
+        $path = trim($path, '/');
76
+
77
+        if (!$path) {
78
+            $path = '.';
79
+        }
80
+
81
+        return $path;
82
+    }
83
+
84
+    private function isRoot($path) {
85
+        return $path === '.';
86
+    }
87
+
88
+    private function cleanKey($path) {
89
+        if ($this->isRoot($path)) {
90
+            return '/';
91
+        }
92
+        return $path;
93
+    }
94
+
95
+    private function clearCache() {
96
+        $this->objectCache = new CappedMemoryCache();
97
+    }
98
+
99
+    private function invalidateCache($key) {
100
+        unset($this->objectCache[$key]);
101
+        $keys = array_keys($this->objectCache->getData());
102
+        $keyLength = strlen($key);
103
+        foreach ($keys as $existingKey) {
104
+            if (substr($existingKey, 0, $keyLength) === $key) {
105
+                unset($this->objectCache[$existingKey]);
106
+            }
107
+        }
108
+    }
109
+
110
+    /**
111
+     * @param $key
112
+     * @return Result|boolean
113
+     */
114
+    private function headObject($key) {
115
+        if (!isset($this->objectCache[$key])) {
116
+            try {
117
+                $this->objectCache[$key] = $this->getConnection()->headObject(array(
118
+                    'Bucket' => $this->bucket,
119
+                    'Key' => $key
120
+                ));
121
+            } catch (S3Exception $e) {
122
+                if ($e->getStatusCode() >= 500) {
123
+                    throw $e;
124
+                }
125
+                $this->objectCache[$key] = false;
126
+            }
127
+        }
128
+
129
+        return $this->objectCache[$key];
130
+    }
131
+
132
+    /**
133
+     * Updates old storage ids (v0.2.1 and older) that are based on key and secret to new ones based on the bucket name.
134
+     * TODO Do this in an update.php. requires iterating over all users and loading the mount.json from their home
135
+     *
136
+     * @param array $params
137
+     */
138
+    public function updateLegacyId(array $params) {
139
+        $oldId = 'amazon::' . $params['key'] . md5($params['secret']);
140
+
141
+        // find by old id or bucket
142
+        $stmt = \OC::$server->getDatabaseConnection()->prepare(
143
+            'SELECT `numeric_id`, `id` FROM `*PREFIX*storages` WHERE `id` IN (?, ?)'
144
+        );
145
+        $stmt->execute(array($oldId, $this->id));
146
+        while ($row = $stmt->fetch()) {
147
+            $storages[$row['id']] = $row['numeric_id'];
148
+        }
149
+
150
+        if (isset($storages[$this->id]) && isset($storages[$oldId])) {
151
+            // if both ids exist, delete the old storage and corresponding filecache entries
152
+            \OC\Files\Cache\Storage::remove($oldId);
153
+        } else if (isset($storages[$oldId])) {
154
+            // if only the old id exists do an update
155
+            $stmt = \OC::$server->getDatabaseConnection()->prepare(
156
+                'UPDATE `*PREFIX*storages` SET `id` = ? WHERE `id` = ?'
157
+            );
158
+            $stmt->execute(array($this->id, $oldId));
159
+        }
160
+        // only the bucket based id may exist, do nothing
161
+    }
162
+
163
+    /**
164
+     * Remove a file or folder
165
+     *
166
+     * @param string $path
167
+     * @return bool
168
+     */
169
+    protected function remove($path) {
170
+        // remember fileType to reduce http calls
171
+        $fileType = $this->filetype($path);
172
+        if ($fileType === 'dir') {
173
+            return $this->rmdir($path);
174
+        } else if ($fileType === 'file') {
175
+            return $this->unlink($path);
176
+        } else {
177
+            return false;
178
+        }
179
+    }
180
+
181
+    public function mkdir($path) {
182
+        $path = $this->normalizePath($path);
183
+
184
+        if ($this->is_dir($path)) {
185
+            return false;
186
+        }
187
+
188
+        try {
189
+            $this->getConnection()->putObject(array(
190
+                'Bucket' => $this->bucket,
191
+                'Key' => $path . '/',
192
+                'Body' => '',
193
+                'ContentType' => 'httpd/unix-directory'
194
+            ));
195
+            $this->testTimeout();
196
+        } catch (S3Exception $e) {
197
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
198
+            return false;
199
+        }
200
+
201
+        $this->invalidateCache($path);
202
+
203
+        return true;
204
+    }
205
+
206
+    public function file_exists($path) {
207
+        return $this->filetype($path) !== false;
208
+    }
209
+
210
+
211
+    public function rmdir($path) {
212
+        $path = $this->normalizePath($path);
213
+
214
+        if ($this->isRoot($path)) {
215
+            return $this->clearBucket();
216
+        }
217
+
218
+        if (!$this->file_exists($path)) {
219
+            return false;
220
+        }
221
+
222
+        $this->invalidateCache($path);
223
+        return $this->batchDelete($path);
224
+    }
225
+
226
+    protected function clearBucket() {
227
+        $this->clearCache();
228
+        try {
229
+            $this->getConnection()->clearBucket($this->bucket);
230
+            return true;
231
+            // clearBucket() is not working with Ceph, so if it fails we try the slower approach
232
+        } catch (\Exception $e) {
233
+            return $this->batchDelete();
234
+        }
235
+    }
236
+
237
+    private function batchDelete($path = null) {
238
+        $params = array(
239
+            'Bucket' => $this->bucket
240
+        );
241
+        if ($path !== null) {
242
+            $params['Prefix'] = $path . '/';
243
+        }
244
+        try {
245
+            $connection = $this->getConnection();
246
+            // Since there are no real directories on S3, we need
247
+            // to delete all objects prefixed with the path.
248
+            do {
249
+                // instead of the iterator, manually loop over the list ...
250
+                $objects = $connection->listObjects($params);
251
+                // ... so we can delete the files in batches
252
+                if (isset($objects['Contents'])) {
253
+                    $connection->deleteObjects([
254
+                        'Bucket' => $this->bucket,
255
+                        'Delete' => [
256
+                            'Objects' => $objects['Contents']
257
+                        ]
258
+                    ]);
259
+                    $this->testTimeout();
260
+                }
261
+                // we reached the end when the list is no longer truncated
262
+            } while ($objects['IsTruncated']);
263
+        } catch (S3Exception $e) {
264
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
265
+            return false;
266
+        }
267
+        return true;
268
+    }
269
+
270
+    public function opendir($path) {
271
+        $path = $this->normalizePath($path);
272
+
273
+        if ($this->isRoot($path)) {
274
+            $path = '';
275
+        } else {
276
+            $path .= '/';
277
+        }
278
+
279
+        try {
280
+            $files = array();
281
+            $results = $this->getConnection()->getPaginator('ListObjects', [
282
+                'Bucket' => $this->bucket,
283
+                'Delimiter' => '/',
284
+                'Prefix' => $path,
285
+            ]);
286
+
287
+            foreach ($results as $result) {
288
+                // sub folders
289
+                if (is_array($result['CommonPrefixes'])) {
290
+                    foreach ($result['CommonPrefixes'] as $prefix) {
291
+                        $files[] = substr(trim($prefix['Prefix'], '/'), strlen($path));
292
+                    }
293
+                }
294
+                foreach ($result['Contents'] as $object) {
295
+                    if (isset($object['Key']) && $object['Key'] === $path) {
296
+                        // it's the directory itself, skip
297
+                        continue;
298
+                    }
299
+                    $file = basename(
300
+                        isset($object['Key']) ? $object['Key'] : $object['Prefix']
301
+                    );
302
+                    $files[] = $file;
303
+                }
304
+            }
305
+
306
+            return IteratorDirectory::wrap($files);
307
+        } catch (S3Exception $e) {
308
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
309
+            return false;
310
+        }
311
+    }
312
+
313
+    public function stat($path) {
314
+        $path = $this->normalizePath($path);
315
+
316
+        try {
317
+            $stat = array();
318
+            if ($this->is_dir($path)) {
319
+                //folders don't really exist
320
+                $stat['size'] = -1; //unknown
321
+                $stat['mtime'] = time() - $this->rescanDelay * 1000;
322
+            } else {
323
+                $result = $this->headObject($path);
324
+
325
+                $stat['size'] = $result['ContentLength'] ? $result['ContentLength'] : 0;
326
+                if (isset($result['Metadata']['lastmodified'])) {
327
+                    $stat['mtime'] = strtotime($result['Metadata']['lastmodified']);
328
+                } else {
329
+                    $stat['mtime'] = strtotime($result['LastModified']);
330
+                }
331
+            }
332
+            $stat['atime'] = time();
333
+
334
+            return $stat;
335
+        } catch (S3Exception $e) {
336
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
337
+            return false;
338
+        }
339
+    }
340
+
341
+    public function is_dir($path) {
342
+        $path = $this->normalizePath($path);
343
+        try {
344
+            return $this->isRoot($path) || $this->headObject($path . '/');
345
+        } catch (S3Exception $e) {
346
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
347
+            return false;
348
+        }
349
+    }
350
+
351
+    public function filetype($path) {
352
+        $path = $this->normalizePath($path);
353
+
354
+        if ($this->isRoot($path)) {
355
+            return 'dir';
356
+        }
357
+
358
+        try {
359
+            if ($this->headObject($path)) {
360
+                return 'file';
361
+            }
362
+            if ($this->headObject($path . '/')) {
363
+                return 'dir';
364
+            }
365
+        } catch (S3Exception $e) {
366
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
367
+            return false;
368
+        }
369
+
370
+        return false;
371
+    }
372
+
373
+    public function getPermissions($path) {
374
+        $type = $this->filetype($path);
375
+        if (!$type) {
376
+            return 0;
377
+        }
378
+        return $type === 'dir' ? Constants::PERMISSION_ALL : Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
379
+    }
380
+
381
+    public function unlink($path) {
382
+        $path = $this->normalizePath($path);
383
+
384
+        if ($this->is_dir($path)) {
385
+            return $this->rmdir($path);
386
+        }
387
+
388
+        try {
389
+            $this->deleteObject($path);
390
+            $this->invalidateCache($path);
391
+        } catch (S3Exception $e) {
392
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
393
+            return false;
394
+        }
395
+
396
+        return true;
397
+    }
398
+
399
+    public function fopen($path, $mode) {
400
+        $path = $this->normalizePath($path);
401
+
402
+        switch ($mode) {
403
+            case 'r':
404
+            case 'rb':
405
+                try {
406
+                    return $this->readObject($path);
407
+                } catch (S3Exception $e) {
408
+                    \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
409
+                    return false;
410
+                }
411
+            case 'w':
412
+            case 'wb':
413
+                $tmpFile = \OCP\Files::tmpFile();
414
+
415
+                $handle = fopen($tmpFile, 'w');
416
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
417
+                    $this->writeBack($tmpFile, $path);
418
+                });
419
+            case 'a':
420
+            case 'ab':
421
+            case 'r+':
422
+            case 'w+':
423
+            case 'wb+':
424
+            case 'a+':
425
+            case 'x':
426
+            case 'x+':
427
+            case 'c':
428
+            case 'c+':
429
+                if (strrpos($path, '.') !== false) {
430
+                    $ext = substr($path, strrpos($path, '.'));
431
+                } else {
432
+                    $ext = '';
433
+                }
434
+                $tmpFile = \OCP\Files::tmpFile($ext);
435
+                if ($this->file_exists($path)) {
436
+                    $source = $this->readObject($path);
437
+                    file_put_contents($tmpFile, $source);
438
+                }
439
+
440
+                $handle = fopen($tmpFile, $mode);
441
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
442
+                    $this->writeBack($tmpFile, $path);
443
+                });
444
+        }
445
+        return false;
446
+    }
447
+
448
+    public function touch($path, $mtime = null) {
449
+        $path = $this->normalizePath($path);
450
+
451
+        $metadata = array();
452
+        if (is_null($mtime)) {
453
+            $mtime = time();
454
+        }
455
+        $metadata = [
456
+            'lastmodified' => gmdate(\DateTime::RFC1123, $mtime)
457
+        ];
458
+
459
+        $fileType = $this->filetype($path);
460
+        try {
461
+            if ($fileType !== false) {
462
+                if ($fileType === 'dir' && !$this->isRoot($path)) {
463
+                    $path .= '/';
464
+                }
465
+                $this->getConnection()->copyObject([
466
+                    'Bucket' => $this->bucket,
467
+                    'Key' => $this->cleanKey($path),
468
+                    'Metadata' => $metadata,
469
+                    'CopySource' => $this->bucket . '/' . $path,
470
+                    'MetadataDirective' => 'REPLACE',
471
+                ]);
472
+                $this->testTimeout();
473
+            } else {
474
+                $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
475
+                $this->getConnection()->putObject([
476
+                    'Bucket' => $this->bucket,
477
+                    'Key' => $this->cleanKey($path),
478
+                    'Metadata' => $metadata,
479
+                    'Body' => '',
480
+                    'ContentType' => $mimeType,
481
+                    'MetadataDirective' => 'REPLACE',
482
+                ]);
483
+                $this->testTimeout();
484
+            }
485
+        } catch (S3Exception $e) {
486
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
487
+            return false;
488
+        }
489
+
490
+        $this->invalidateCache($path);
491
+        return true;
492
+    }
493
+
494
+    public function copy($path1, $path2) {
495
+        $path1 = $this->normalizePath($path1);
496
+        $path2 = $this->normalizePath($path2);
497
+
498
+        if ($this->is_file($path1)) {
499
+            try {
500
+                $this->getConnection()->copyObject(array(
501
+                    'Bucket' => $this->bucket,
502
+                    'Key' => $this->cleanKey($path2),
503
+                    'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
504
+                ));
505
+                $this->testTimeout();
506
+            } catch (S3Exception $e) {
507
+                \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
508
+                return false;
509
+            }
510
+        } else {
511
+            $this->remove($path2);
512
+
513
+            try {
514
+                $this->getConnection()->copyObject(array(
515
+                    'Bucket' => $this->bucket,
516
+                    'Key' => $path2 . '/',
517
+                    'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
518
+                ));
519
+                $this->testTimeout();
520
+            } catch (S3Exception $e) {
521
+                \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
522
+                return false;
523
+            }
524
+
525
+            $dh = $this->opendir($path1);
526
+            if (is_resource($dh)) {
527
+                while (($file = readdir($dh)) !== false) {
528
+                    if (\OC\Files\Filesystem::isIgnoredDir($file)) {
529
+                        continue;
530
+                    }
531
+
532
+                    $source = $path1 . '/' . $file;
533
+                    $target = $path2 . '/' . $file;
534
+                    $this->copy($source, $target);
535
+                }
536
+            }
537
+        }
538
+
539
+        $this->invalidateCache($path2);
540
+
541
+        return true;
542
+    }
543
+
544
+    public function rename($path1, $path2) {
545
+        $path1 = $this->normalizePath($path1);
546
+        $path2 = $this->normalizePath($path2);
547
+
548
+        if ($this->is_file($path1)) {
549
+
550
+            if ($this->copy($path1, $path2) === false) {
551
+                return false;
552
+            }
553
+
554
+            if ($this->unlink($path1) === false) {
555
+                $this->unlink($path2);
556
+                return false;
557
+            }
558
+        } else {
559
+
560
+            if ($this->copy($path1, $path2) === false) {
561
+                return false;
562
+            }
563
+
564
+            if ($this->rmdir($path1) === false) {
565
+                $this->rmdir($path2);
566
+                return false;
567
+            }
568
+        }
569
+
570
+        return true;
571
+    }
572
+
573
+    public function test() {
574
+        $this->getConnection()->headBucket([
575
+            'Bucket' => $this->bucket
576
+        ]);
577
+        return true;
578
+    }
579
+
580
+    public function getId() {
581
+        return $this->id;
582
+    }
583
+
584
+    public function writeBack($tmpFile, $path) {
585
+        try {
586
+            $source = fopen($tmpFile, 'r');
587
+            $this->writeObject($path, $source);
588
+            $this->invalidateCache($path);
589
+            fclose($source);
590
+
591
+            unlink($tmpFile);
592
+            return true;
593
+        } catch (S3Exception $e) {
594
+            \OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
595
+            return false;
596
+        }
597
+    }
598
+
599
+    /**
600
+     * check if curl is installed
601
+     */
602
+    public static function checkDependencies() {
603
+        return true;
604
+    }
605 605
 
606 606
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
 	 * @param array $params
137 137
 	 */
138 138
 	public function updateLegacyId(array $params) {
139
-		$oldId = 'amazon::' . $params['key'] . md5($params['secret']);
139
+		$oldId = 'amazon::'.$params['key'].md5($params['secret']);
140 140
 
141 141
 		// find by old id or bucket
142 142
 		$stmt = \OC::$server->getDatabaseConnection()->prepare(
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
 		try {
189 189
 			$this->getConnection()->putObject(array(
190 190
 				'Bucket' => $this->bucket,
191
-				'Key' => $path . '/',
191
+				'Key' => $path.'/',
192 192
 				'Body' => '',
193 193
 				'ContentType' => 'httpd/unix-directory'
194 194
 			));
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
 			'Bucket' => $this->bucket
240 240
 		);
241 241
 		if ($path !== null) {
242
-			$params['Prefix'] = $path . '/';
242
+			$params['Prefix'] = $path.'/';
243 243
 		}
244 244
 		try {
245 245
 			$connection = $this->getConnection();
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
 	public function is_dir($path) {
342 342
 		$path = $this->normalizePath($path);
343 343
 		try {
344
-			return $this->isRoot($path) || $this->headObject($path . '/');
344
+			return $this->isRoot($path) || $this->headObject($path.'/');
345 345
 		} catch (S3Exception $e) {
346 346
 			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
347 347
 			return false;
@@ -359,7 +359,7 @@  discard block
 block discarded – undo
359 359
 			if ($this->headObject($path)) {
360 360
 				return 'file';
361 361
 			}
362
-			if ($this->headObject($path . '/')) {
362
+			if ($this->headObject($path.'/')) {
363 363
 				return 'dir';
364 364
 			}
365 365
 		} catch (S3Exception $e) {
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
 				$tmpFile = \OCP\Files::tmpFile();
414 414
 
415 415
 				$handle = fopen($tmpFile, 'w');
416
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
416
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
417 417
 					$this->writeBack($tmpFile, $path);
418 418
 				});
419 419
 			case 'a':
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
 				}
439 439
 
440 440
 				$handle = fopen($tmpFile, $mode);
441
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
441
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
442 442
 					$this->writeBack($tmpFile, $path);
443 443
 				});
444 444
 		}
@@ -466,7 +466,7 @@  discard block
 block discarded – undo
466 466
 					'Bucket' => $this->bucket,
467 467
 					'Key' => $this->cleanKey($path),
468 468
 					'Metadata' => $metadata,
469
-					'CopySource' => $this->bucket . '/' . $path,
469
+					'CopySource' => $this->bucket.'/'.$path,
470 470
 					'MetadataDirective' => 'REPLACE',
471 471
 				]);
472 472
 				$this->testTimeout();
@@ -500,7 +500,7 @@  discard block
 block discarded – undo
500 500
 				$this->getConnection()->copyObject(array(
501 501
 					'Bucket' => $this->bucket,
502 502
 					'Key' => $this->cleanKey($path2),
503
-					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
503
+					'CopySource' => S3Client::encodeKey($this->bucket.'/'.$path1)
504 504
 				));
505 505
 				$this->testTimeout();
506 506
 			} catch (S3Exception $e) {
@@ -513,8 +513,8 @@  discard block
 block discarded – undo
513 513
 			try {
514 514
 				$this->getConnection()->copyObject(array(
515 515
 					'Bucket' => $this->bucket,
516
-					'Key' => $path2 . '/',
517
-					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
516
+					'Key' => $path2.'/',
517
+					'CopySource' => S3Client::encodeKey($this->bucket.'/'.$path1.'/')
518 518
 				));
519 519
 				$this->testTimeout();
520 520
 			} catch (S3Exception $e) {
@@ -529,8 +529,8 @@  discard block
 block discarded – undo
529 529
 						continue;
530 530
 					}
531 531
 
532
-					$source = $path1 . '/' . $file;
533
-					$target = $path2 . '/' . $file;
532
+					$source = $path1.'/'.$file;
533
+					$target = $path2.'/'.$file;
534 534
 					$this->copy($source, $target);
535 535
 				}
536 536
 			}
Please login to merge, or discard this patch.
apps/files/ajax/list.php 1 patch
Indentation   +56 added lines, -56 removed lines patch added patch discarded remove patch
@@ -36,72 +36,72 @@
 block discarded – undo
36 36
 $dir = \OC\Files\Filesystem::normalizePath($dir);
37 37
 
38 38
 try {
39
-	$dirInfo = \OC\Files\Filesystem::getFileInfo($dir);
40
-	if (!$dirInfo || !$dirInfo->getType() === 'dir') {
41
-		header("HTTP/1.0 404 Not Found");
42
-		exit();
43
-	}
39
+    $dirInfo = \OC\Files\Filesystem::getFileInfo($dir);
40
+    if (!$dirInfo || !$dirInfo->getType() === 'dir') {
41
+        header("HTTP/1.0 404 Not Found");
42
+        exit();
43
+    }
44 44
 
45
-	$data = array();
46
-	$baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir=';
45
+    $data = array();
46
+    $baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir=';
47 47
 
48
-	$permissions = $dirInfo->getPermissions();
48
+    $permissions = $dirInfo->getPermissions();
49 49
 
50
-	$sortAttribute = isset($_GET['sort']) ? (string)$_GET['sort'] : 'name';
51
-	$sortDirection = isset($_GET['sortdirection']) ? ($_GET['sortdirection'] === 'desc') : false;
52
-	$mimetypeFilters = isset($_GET['mimetypes']) ? json_decode($_GET['mimetypes']) : '';
50
+    $sortAttribute = isset($_GET['sort']) ? (string)$_GET['sort'] : 'name';
51
+    $sortDirection = isset($_GET['sortdirection']) ? ($_GET['sortdirection'] === 'desc') : false;
52
+    $mimetypeFilters = isset($_GET['mimetypes']) ? json_decode($_GET['mimetypes']) : '';
53 53
 
54
-	$files = [];
55
-	// Clean up duplicates from array
56
-	if (is_array($mimetypeFilters) && count($mimetypeFilters)) {
57
-		$mimetypeFilters = array_unique($mimetypeFilters);
54
+    $files = [];
55
+    // Clean up duplicates from array
56
+    if (is_array($mimetypeFilters) && count($mimetypeFilters)) {
57
+        $mimetypeFilters = array_unique($mimetypeFilters);
58 58
 
59
-		if (!in_array('httpd/unix-directory', $mimetypeFilters)) {
60
-			// append folder filter to be able to browse folders
61
-			$mimetypeFilters[] = 'httpd/unix-directory';
62
-		}
59
+        if (!in_array('httpd/unix-directory', $mimetypeFilters)) {
60
+            // append folder filter to be able to browse folders
61
+            $mimetypeFilters[] = 'httpd/unix-directory';
62
+        }
63 63
 
64
-		// create filelist with mimetype filter - as getFiles only supports on
65
-		// mimetype filter at once we will filter this folder for each
66
-		// mimetypeFilter
67
-		foreach ($mimetypeFilters as $mimetypeFilter) {
68
-			$files = array_merge($files, \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection, $mimetypeFilter));
69
-		}
64
+        // create filelist with mimetype filter - as getFiles only supports on
65
+        // mimetype filter at once we will filter this folder for each
66
+        // mimetypeFilter
67
+        foreach ($mimetypeFilters as $mimetypeFilter) {
68
+            $files = array_merge($files, \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection, $mimetypeFilter));
69
+        }
70 70
 
71
-		// sort the files accordingly
72
-		$files = \OCA\Files\Helper::sortFiles($files, $sortAttribute, $sortDirection);
73
-	} else {
74
-		// create file list without mimetype filter
75
-		$files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection);
76
-	}
71
+        // sort the files accordingly
72
+        $files = \OCA\Files\Helper::sortFiles($files, $sortAttribute, $sortDirection);
73
+    } else {
74
+        // create file list without mimetype filter
75
+        $files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection);
76
+    }
77 77
 
78
-	$data['directory'] = $dir;
79
-	$data['files'] = \OCA\Files\Helper::formatFileInfos($files);
80
-	$data['permissions'] = $permissions;
78
+    $data['directory'] = $dir;
79
+    $data['files'] = \OCA\Files\Helper::formatFileInfos($files);
80
+    $data['permissions'] = $permissions;
81 81
 
82
-	OCP\JSON::success(array('data' => $data));
82
+    OCP\JSON::success(array('data' => $data));
83 83
 } catch (\OCP\Files\StorageNotAvailableException $e) {
84
-	\OC::$server->getLogger()->logException($e, ['app' => 'files']);
85
-	OCP\JSON::error([
86
-		'data' => [
87
-			'exception' => StorageNotAvailableException::class,
88
-			'message' => $l->t('Storage is temporarily not available')
89
-		]
90
-	]);
84
+    \OC::$server->getLogger()->logException($e, ['app' => 'files']);
85
+    OCP\JSON::error([
86
+        'data' => [
87
+            'exception' => StorageNotAvailableException::class,
88
+            'message' => $l->t('Storage is temporarily not available')
89
+        ]
90
+    ]);
91 91
 } catch (\OCP\Files\StorageInvalidException $e) {
92
-	\OC::$server->getLogger()->logException($e, ['app' => 'files']);
93
-	OCP\JSON::error(array(
94
-		'data' => array(
95
-			'exception' => StorageInvalidException::class,
96
-			'message' => $l->t('Storage invalid')
97
-		)
98
-	));
92
+    \OC::$server->getLogger()->logException($e, ['app' => 'files']);
93
+    OCP\JSON::error(array(
94
+        'data' => array(
95
+            'exception' => StorageInvalidException::class,
96
+            'message' => $l->t('Storage invalid')
97
+        )
98
+    ));
99 99
 } catch (\Exception $e) {
100
-	\OC::$server->getLogger()->logException($e, ['app' => 'files']);
101
-	OCP\JSON::error(array(
102
-		'data' => array(
103
-			'exception' => \Exception::class,
104
-			'message' => $l->t('Unknown error')
105
-		)
106
-	));
100
+    \OC::$server->getLogger()->logException($e, ['app' => 'files']);
101
+    OCP\JSON::error(array(
102
+        'data' => array(
103
+            'exception' => \Exception::class,
104
+            'message' => $l->t('Unknown error')
105
+        )
106
+    ));
107 107
 }
Please login to merge, or discard this patch.
lib/base.php 1 patch
Indentation   +991 added lines, -991 removed lines patch added patch discarded remove patch
@@ -67,997 +67,997 @@
 block discarded – undo
67 67
  * OC_autoload!
68 68
  */
69 69
 class OC {
70
-	/**
71
-	 * Associative array for autoloading. classname => filename
72
-	 */
73
-	public static $CLASSPATH = array();
74
-	/**
75
-	 * The installation path for Nextcloud  on the server (e.g. /srv/http/nextcloud)
76
-	 */
77
-	public static $SERVERROOT = '';
78
-	/**
79
-	 * the current request path relative to the Nextcloud root (e.g. files/index.php)
80
-	 */
81
-	private static $SUBURI = '';
82
-	/**
83
-	 * the Nextcloud root path for http requests (e.g. nextcloud/)
84
-	 */
85
-	public static $WEBROOT = '';
86
-	/**
87
-	 * The installation path array of the apps folder on the server (e.g. /srv/http/nextcloud) 'path' and
88
-	 * web path in 'url'
89
-	 */
90
-	public static $APPSROOTS = array();
91
-
92
-	/**
93
-	 * @var string
94
-	 */
95
-	public static $configDir;
96
-
97
-	/**
98
-	 * requested app
99
-	 */
100
-	public static $REQUESTEDAPP = '';
101
-
102
-	/**
103
-	 * check if Nextcloud runs in cli mode
104
-	 */
105
-	public static $CLI = false;
106
-
107
-	/**
108
-	 * @var \OC\Autoloader $loader
109
-	 */
110
-	public static $loader = null;
111
-
112
-	/** @var \Composer\Autoload\ClassLoader $composerAutoloader */
113
-	public static $composerAutoloader = null;
114
-
115
-	/**
116
-	 * @var \OC\Server
117
-	 */
118
-	public static $server = null;
119
-
120
-	/**
121
-	 * @var \OC\Config
122
-	 */
123
-	private static $config = null;
124
-
125
-	/**
126
-	 * @throws \RuntimeException when the 3rdparty directory is missing or
127
-	 * the app path list is empty or contains an invalid path
128
-	 */
129
-	public static function initPaths() {
130
-		if(defined('PHPUNIT_CONFIG_DIR')) {
131
-			self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
132
-		} elseif(defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
133
-			self::$configDir = OC::$SERVERROOT . '/tests/config/';
134
-		} elseif($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
135
-			self::$configDir = rtrim($dir, '/') . '/';
136
-		} else {
137
-			self::$configDir = OC::$SERVERROOT . '/config/';
138
-		}
139
-		self::$config = new \OC\Config(self::$configDir);
140
-
141
-		OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
142
-		/**
143
-		 * FIXME: The following lines are required because we can't yet instantiate
144
-		 *        \OC::$server->getRequest() since \OC::$server does not yet exist.
145
-		 */
146
-		$params = [
147
-			'server' => [
148
-				'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
149
-				'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
150
-			],
151
-		];
152
-		$fakeRequest = new \OC\AppFramework\Http\Request($params, null, new \OC\AllConfig(new \OC\SystemConfig(self::$config)));
153
-		$scriptName = $fakeRequest->getScriptName();
154
-		if (substr($scriptName, -1) == '/') {
155
-			$scriptName .= 'index.php';
156
-			//make sure suburi follows the same rules as scriptName
157
-			if (substr(OC::$SUBURI, -9) != 'index.php') {
158
-				if (substr(OC::$SUBURI, -1) != '/') {
159
-					OC::$SUBURI = OC::$SUBURI . '/';
160
-				}
161
-				OC::$SUBURI = OC::$SUBURI . 'index.php';
162
-			}
163
-		}
164
-
165
-
166
-		if (OC::$CLI) {
167
-			OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
168
-		} else {
169
-			if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
170
-				OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
171
-
172
-				if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
173
-					OC::$WEBROOT = '/' . OC::$WEBROOT;
174
-				}
175
-			} else {
176
-				// The scriptName is not ending with OC::$SUBURI
177
-				// This most likely means that we are calling from CLI.
178
-				// However some cron jobs still need to generate
179
-				// a web URL, so we use overwritewebroot as a fallback.
180
-				OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
181
-			}
182
-
183
-			// Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
184
-			// slash which is required by URL generation.
185
-			if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
186
-					substr($_SERVER['REQUEST_URI'], -1) !== '/') {
187
-				header('Location: '.\OC::$WEBROOT.'/');
188
-				exit();
189
-			}
190
-		}
191
-
192
-		// search the apps folder
193
-		$config_paths = self::$config->getValue('apps_paths', array());
194
-		if (!empty($config_paths)) {
195
-			foreach ($config_paths as $paths) {
196
-				if (isset($paths['url']) && isset($paths['path'])) {
197
-					$paths['url'] = rtrim($paths['url'], '/');
198
-					$paths['path'] = rtrim($paths['path'], '/');
199
-					OC::$APPSROOTS[] = $paths;
200
-				}
201
-			}
202
-		} elseif (file_exists(OC::$SERVERROOT . '/apps')) {
203
-			OC::$APPSROOTS[] = array('path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true);
204
-		} elseif (file_exists(OC::$SERVERROOT . '/../apps')) {
205
-			OC::$APPSROOTS[] = array(
206
-				'path' => rtrim(dirname(OC::$SERVERROOT), '/') . '/apps',
207
-				'url' => '/apps',
208
-				'writable' => true
209
-			);
210
-		}
211
-
212
-		if (empty(OC::$APPSROOTS)) {
213
-			throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
214
-				. ' or the folder above. You can also configure the location in the config.php file.');
215
-		}
216
-		$paths = array();
217
-		foreach (OC::$APPSROOTS as $path) {
218
-			$paths[] = $path['path'];
219
-			if (!is_dir($path['path'])) {
220
-				throw new \RuntimeException(sprintf('App directory "%s" not found! Please put the Nextcloud apps folder in the'
221
-					. ' Nextcloud folder or the folder above. You can also configure the location in the'
222
-					. ' config.php file.', $path['path']));
223
-			}
224
-		}
225
-
226
-		// set the right include path
227
-		set_include_path(
228
-			implode(PATH_SEPARATOR, $paths)
229
-		);
230
-	}
231
-
232
-	public static function checkConfig() {
233
-		$l = \OC::$server->getL10N('lib');
234
-
235
-		// Create config if it does not already exist
236
-		$configFilePath = self::$configDir .'/config.php';
237
-		if(!file_exists($configFilePath)) {
238
-			@touch($configFilePath);
239
-		}
240
-
241
-		// Check if config is writable
242
-		$configFileWritable = is_writable($configFilePath);
243
-		if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
244
-			|| !$configFileWritable && \OCP\Util::needUpgrade()) {
245
-
246
-			$urlGenerator = \OC::$server->getURLGenerator();
247
-
248
-			if (self::$CLI) {
249
-				echo $l->t('Cannot write into "config" directory!')."\n";
250
-				echo $l->t('This can usually be fixed by giving the webserver write access to the config directory')."\n";
251
-				echo "\n";
252
-				echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-dir_permissions') ])."\n";
253
-				exit;
254
-			} else {
255
-				OC_Template::printErrorPage(
256
-					$l->t('Cannot write into "config" directory!'),
257
-					$l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
258
-					 [ $urlGenerator->linkToDocs('admin-dir_permissions') ])
259
-				);
260
-			}
261
-		}
262
-	}
263
-
264
-	public static function checkInstalled() {
265
-		if (defined('OC_CONSOLE')) {
266
-			return;
267
-		}
268
-		// Redirect to installer if not installed
269
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false) && OC::$SUBURI !== '/index.php' && OC::$SUBURI !== '/status.php') {
270
-			if (OC::$CLI) {
271
-				throw new Exception('Not installed');
272
-			} else {
273
-				$url = OC::$WEBROOT . '/index.php';
274
-				header('Location: ' . $url);
275
-			}
276
-			exit();
277
-		}
278
-	}
279
-
280
-	public static function checkMaintenanceMode() {
281
-		// Allow ajax update script to execute without being stopped
282
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false) && OC::$SUBURI != '/core/ajax/update.php') {
283
-			// send http status 503
284
-			header('HTTP/1.1 503 Service Temporarily Unavailable');
285
-			header('Status: 503 Service Temporarily Unavailable');
286
-			header('Retry-After: 120');
287
-
288
-			// render error page
289
-			$template = new OC_Template('', 'update.user', 'guest');
290
-			OC_Util::addScript('maintenance-check');
291
-			OC_Util::addStyle('core', 'guest');
292
-			$template->printPage();
293
-			die();
294
-		}
295
-	}
296
-
297
-	/**
298
-	 * Prints the upgrade page
299
-	 *
300
-	 * @param \OC\SystemConfig $systemConfig
301
-	 */
302
-	private static function printUpgradePage(\OC\SystemConfig $systemConfig) {
303
-		$disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
304
-		$tooBig = false;
305
-		if (!$disableWebUpdater) {
306
-			$apps = \OC::$server->getAppManager();
307
-			if ($apps->isInstalled('user_ldap')) {
308
-				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
309
-
310
-				$result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
311
-					->from('ldap_user_mapping')
312
-					->execute();
313
-				$row = $result->fetch();
314
-				$result->closeCursor();
315
-
316
-				$tooBig = ($row['user_count'] > 50);
317
-			}
318
-			if (!$tooBig && $apps->isInstalled('user_saml')) {
319
-				$qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
320
-
321
-				$result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
322
-					->from('user_saml_users')
323
-					->execute();
324
-				$row = $result->fetch();
325
-				$result->closeCursor();
326
-
327
-				$tooBig = ($row['user_count'] > 50);
328
-			}
329
-			if (!$tooBig) {
330
-				// count users
331
-				$stats = \OC::$server->getUserManager()->countUsers();
332
-				$totalUsers = array_sum($stats);
333
-				$tooBig = ($totalUsers > 50);
334
-			}
335
-		}
336
-		$ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) &&
337
-			$_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
338
-
339
-		if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
340
-			// send http status 503
341
-			header('HTTP/1.1 503 Service Temporarily Unavailable');
342
-			header('Status: 503 Service Temporarily Unavailable');
343
-			header('Retry-After: 120');
344
-
345
-			// render error page
346
-			$template = new OC_Template('', 'update.use-cli', 'guest');
347
-			$template->assign('productName', 'nextcloud'); // for now
348
-			$template->assign('version', OC_Util::getVersionString());
349
-			$template->assign('tooBig', $tooBig);
350
-
351
-			$template->printPage();
352
-			die();
353
-		}
354
-
355
-		// check whether this is a core update or apps update
356
-		$installedVersion = $systemConfig->getValue('version', '0.0.0');
357
-		$currentVersion = implode('.', \OCP\Util::getVersion());
358
-
359
-		// if not a core upgrade, then it's apps upgrade
360
-		$isAppsOnlyUpgrade = version_compare($currentVersion, $installedVersion, '=');
361
-
362
-		$oldTheme = $systemConfig->getValue('theme');
363
-		$systemConfig->setValue('theme', '');
364
-		OC_Util::addScript('config'); // needed for web root
365
-		OC_Util::addScript('update');
366
-
367
-		/** @var \OC\App\AppManager $appManager */
368
-		$appManager = \OC::$server->getAppManager();
369
-
370
-		$tmpl = new OC_Template('', 'update.admin', 'guest');
371
-		$tmpl->assign('version', OC_Util::getVersionString());
372
-		$tmpl->assign('isAppsOnlyUpgrade', $isAppsOnlyUpgrade);
373
-
374
-		// get third party apps
375
-		$ocVersion = \OCP\Util::getVersion();
376
-		$ocVersion = implode('.', $ocVersion);
377
-		$incompatibleApps = $appManager->getIncompatibleApps($ocVersion);
378
-		$incompatibleShippedApps = [];
379
-		foreach ($incompatibleApps as $appInfo) {
380
-			if ($appManager->isShipped($appInfo['id'])) {
381
-				$incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
382
-			}
383
-		}
384
-
385
-		if (!empty($incompatibleShippedApps)) {
386
-			$l = \OC::$server->getL10N('core');
387
-			$hint = $l->t('The files of the app %$1s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
388
-			throw new \OC\HintException('The files of the app ' . implode(', ', $incompatibleShippedApps) . ' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
389
-		}
390
-
391
-		$tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
392
-		$tmpl->assign('incompatibleAppsList', $incompatibleApps);
393
-		$tmpl->assign('productName', 'Nextcloud'); // for now
394
-		$tmpl->assign('oldTheme', $oldTheme);
395
-		$tmpl->printPage();
396
-	}
397
-
398
-	public static function initSession() {
399
-		if(self::$server->getRequest()->getServerProtocol() === 'https') {
400
-			ini_set('session.cookie_secure', true);
401
-		}
402
-
403
-		// prevents javascript from accessing php session cookies
404
-		ini_set('session.cookie_httponly', 'true');
405
-
406
-		// set the cookie path to the Nextcloud directory
407
-		$cookie_path = OC::$WEBROOT ? : '/';
408
-		ini_set('session.cookie_path', $cookie_path);
409
-
410
-		// Let the session name be changed in the initSession Hook
411
-		$sessionName = OC_Util::getInstanceId();
412
-
413
-		try {
414
-			// Allow session apps to create a custom session object
415
-			$useCustomSession = false;
416
-			$session = self::$server->getSession();
417
-			OC_Hook::emit('OC', 'initSession', array('session' => &$session, 'sessionName' => &$sessionName, 'useCustomSession' => &$useCustomSession));
418
-			if (!$useCustomSession) {
419
-				// set the session name to the instance id - which is unique
420
-				$session = new \OC\Session\Internal($sessionName);
421
-			}
422
-
423
-			$cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
424
-			$session = $cryptoWrapper->wrapSession($session);
425
-			self::$server->setSession($session);
426
-
427
-			// if session can't be started break with http 500 error
428
-		} catch (Exception $e) {
429
-			\OC::$server->getLogger()->logException($e, ['app' => 'base']);
430
-			//show the user a detailed error page
431
-			OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR);
432
-			OC_Template::printExceptionErrorPage($e);
433
-			die();
434
-		}
435
-
436
-		$sessionLifeTime = self::getSessionLifeTime();
437
-
438
-		// session timeout
439
-		if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
440
-			if (isset($_COOKIE[session_name()])) {
441
-				setcookie(session_name(), null, -1, self::$WEBROOT ? : '/');
442
-			}
443
-			\OC::$server->getUserSession()->logout();
444
-		}
445
-
446
-		$session->set('LAST_ACTIVITY', time());
447
-	}
448
-
449
-	/**
450
-	 * @return string
451
-	 */
452
-	private static function getSessionLifeTime() {
453
-		return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
454
-	}
455
-
456
-	public static function loadAppClassPaths() {
457
-		foreach (OC_App::getEnabledApps() as $app) {
458
-			$appPath = OC_App::getAppPath($app);
459
-			if ($appPath === false) {
460
-				continue;
461
-			}
462
-
463
-			$file = $appPath . '/appinfo/classpath.php';
464
-			if (file_exists($file)) {
465
-				require_once $file;
466
-			}
467
-		}
468
-	}
469
-
470
-	/**
471
-	 * Try to set some values to the required Nextcloud default
472
-	 */
473
-	public static function setRequiredIniValues() {
474
-		@ini_set('default_charset', 'UTF-8');
475
-		@ini_set('gd.jpeg_ignore_warning', '1');
476
-	}
477
-
478
-	/**
479
-	 * Send the same site cookies
480
-	 */
481
-	private static function sendSameSiteCookies() {
482
-		$cookieParams = session_get_cookie_params();
483
-		$secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
484
-		$policies = [
485
-			'lax',
486
-			'strict',
487
-		];
488
-
489
-		// Append __Host to the cookie if it meets the requirements
490
-		$cookiePrefix = '';
491
-		if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
492
-			$cookiePrefix = '__Host-';
493
-		}
494
-
495
-		foreach($policies as $policy) {
496
-			header(
497
-				sprintf(
498
-					'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
499
-					$cookiePrefix,
500
-					$policy,
501
-					$cookieParams['path'],
502
-					$policy
503
-				),
504
-				false
505
-			);
506
-		}
507
-	}
508
-
509
-	/**
510
-	 * Same Site cookie to further mitigate CSRF attacks. This cookie has to
511
-	 * be set in every request if cookies are sent to add a second level of
512
-	 * defense against CSRF.
513
-	 *
514
-	 * If the cookie is not sent this will set the cookie and reload the page.
515
-	 * We use an additional cookie since we want to protect logout CSRF and
516
-	 * also we can't directly interfere with PHP's session mechanism.
517
-	 */
518
-	private static function performSameSiteCookieProtection() {
519
-		$request = \OC::$server->getRequest();
520
-
521
-		// Some user agents are notorious and don't really properly follow HTTP
522
-		// specifications. For those, have an automated opt-out. Since the protection
523
-		// for remote.php is applied in base.php as starting point we need to opt out
524
-		// here.
525
-		$incompatibleUserAgents = [
526
-			// OS X Finder
527
-			'/^WebDAVFS/',
528
-		];
529
-		if($request->isUserAgent($incompatibleUserAgents)) {
530
-			return;
531
-		}
532
-
533
-		if(count($_COOKIE) > 0) {
534
-			$requestUri = $request->getScriptName();
535
-			$processingScript = explode('/', $requestUri);
536
-			$processingScript = $processingScript[count($processingScript)-1];
537
-
538
-			// index.php routes are handled in the middleware
539
-			if($processingScript === 'index.php') {
540
-				return;
541
-			}
542
-
543
-			// All other endpoints require the lax and the strict cookie
544
-			if(!$request->passesStrictCookieCheck()) {
545
-				self::sendSameSiteCookies();
546
-				// Debug mode gets access to the resources without strict cookie
547
-				// due to the fact that the SabreDAV browser also lives there.
548
-				if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
549
-					http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
550
-					exit();
551
-				}
552
-			}
553
-		} elseif(!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
554
-			self::sendSameSiteCookies();
555
-		}
556
-	}
557
-
558
-	public static function init() {
559
-		// calculate the root directories
560
-		OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
561
-
562
-		// register autoloader
563
-		$loaderStart = microtime(true);
564
-		require_once __DIR__ . '/autoloader.php';
565
-		self::$loader = new \OC\Autoloader([
566
-			OC::$SERVERROOT . '/lib/private/legacy',
567
-		]);
568
-		if (defined('PHPUNIT_RUN')) {
569
-			self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
570
-		}
571
-		spl_autoload_register(array(self::$loader, 'load'));
572
-		$loaderEnd = microtime(true);
573
-
574
-		self::$CLI = (php_sapi_name() == 'cli');
575
-
576
-		// Add default composer PSR-4 autoloader
577
-		self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
578
-
579
-		try {
580
-			self::initPaths();
581
-			// setup 3rdparty autoloader
582
-			$vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
583
-			if (!file_exists($vendorAutoLoad)) {
584
-				throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
585
-			}
586
-			require_once $vendorAutoLoad;
587
-
588
-		} catch (\RuntimeException $e) {
589
-			if (!self::$CLI) {
590
-				$claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
591
-				$protocol = in_array($claimedProtocol, ['HTTP/1.0', 'HTTP/1.1', 'HTTP/2']) ? $claimedProtocol : 'HTTP/1.1';
592
-				header($protocol . ' ' . OC_Response::STATUS_SERVICE_UNAVAILABLE);
593
-			}
594
-			// we can't use the template error page here, because this needs the
595
-			// DI container which isn't available yet
596
-			print($e->getMessage());
597
-			exit();
598
-		}
599
-
600
-		// setup the basic server
601
-		self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
602
-		\OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
603
-		\OC::$server->getEventLogger()->start('boot', 'Initialize');
604
-
605
-		// Don't display errors and log them
606
-		error_reporting(E_ALL | E_STRICT);
607
-		@ini_set('display_errors', '0');
608
-		@ini_set('log_errors', '1');
609
-
610
-		if(!date_default_timezone_set('UTC')) {
611
-			throw new \RuntimeException('Could not set timezone to UTC');
612
-		}
613
-
614
-		//try to configure php to enable big file uploads.
615
-		//this doesn´t work always depending on the webserver and php configuration.
616
-		//Let´s try to overwrite some defaults anyway
617
-
618
-		//try to set the maximum execution time to 60min
619
-		if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
620
-			@set_time_limit(3600);
621
-		}
622
-		@ini_set('max_execution_time', '3600');
623
-		@ini_set('max_input_time', '3600');
624
-
625
-		//try to set the maximum filesize to 10G
626
-		@ini_set('upload_max_filesize', '10G');
627
-		@ini_set('post_max_size', '10G');
628
-		@ini_set('file_uploads', '50');
629
-
630
-		self::setRequiredIniValues();
631
-		self::handleAuthHeaders();
632
-		self::registerAutoloaderCache();
633
-
634
-		// initialize intl fallback is necessary
635
-		\Patchwork\Utf8\Bootup::initIntl();
636
-		OC_Util::isSetLocaleWorking();
637
-
638
-		if (!defined('PHPUNIT_RUN')) {
639
-			OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger());
640
-			$debug = \OC::$server->getConfig()->getSystemValue('debug', false);
641
-			OC\Log\ErrorHandler::register($debug);
642
-		}
643
-
644
-		\OC::$server->getEventLogger()->start('init_session', 'Initialize session');
645
-		OC_App::loadApps(array('session'));
646
-		if (!self::$CLI) {
647
-			self::initSession();
648
-		}
649
-		\OC::$server->getEventLogger()->end('init_session');
650
-		self::checkConfig();
651
-		self::checkInstalled();
652
-
653
-		OC_Response::addSecurityHeaders();
654
-
655
-		self::performSameSiteCookieProtection();
656
-
657
-		if (!defined('OC_CONSOLE')) {
658
-			$errors = OC_Util::checkServer(\OC::$server->getSystemConfig());
659
-			if (count($errors) > 0) {
660
-				if (self::$CLI) {
661
-					// Convert l10n string into regular string for usage in database
662
-					$staticErrors = [];
663
-					foreach ($errors as $error) {
664
-						echo $error['error'] . "\n";
665
-						echo $error['hint'] . "\n\n";
666
-						$staticErrors[] = [
667
-							'error' => (string)$error['error'],
668
-							'hint' => (string)$error['hint'],
669
-						];
670
-					}
671
-
672
-					try {
673
-						\OC::$server->getConfig()->setAppValue('core', 'cronErrors', json_encode($staticErrors));
674
-					} catch (\Exception $e) {
675
-						echo('Writing to database failed');
676
-					}
677
-					exit(1);
678
-				} else {
679
-					OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
680
-					OC_Util::addStyle('guest');
681
-					OC_Template::printGuestPage('', 'error', array('errors' => $errors));
682
-					exit;
683
-				}
684
-			} elseif (self::$CLI && \OC::$server->getConfig()->getSystemValue('installed', false)) {
685
-				\OC::$server->getConfig()->deleteAppValue('core', 'cronErrors');
686
-			}
687
-		}
688
-		//try to set the session lifetime
689
-		$sessionLifeTime = self::getSessionLifeTime();
690
-		@ini_set('gc_maxlifetime', (string)$sessionLifeTime);
691
-
692
-		$systemConfig = \OC::$server->getSystemConfig();
693
-
694
-		// User and Groups
695
-		if (!$systemConfig->getValue("installed", false)) {
696
-			self::$server->getSession()->set('user_id', '');
697
-		}
698
-
699
-		OC_User::useBackend(new \OC\User\Database());
700
-		\OC::$server->getGroupManager()->addBackend(new \OC\Group\Database());
701
-
702
-		// Subscribe to the hook
703
-		\OCP\Util::connectHook(
704
-			'\OCA\Files_Sharing\API\Server2Server',
705
-			'preLoginNameUsedAsUserName',
706
-			'\OC\User\Database',
707
-			'preLoginNameUsedAsUserName'
708
-		);
709
-
710
-		//setup extra user backends
711
-		if (!\OCP\Util::needUpgrade()) {
712
-			OC_User::setupBackends();
713
-		} else {
714
-			// Run upgrades in incognito mode
715
-			OC_User::setIncognitoMode(true);
716
-		}
717
-
718
-		self::registerCleanupHooks();
719
-		self::registerFilesystemHooks();
720
-		self::registerShareHooks();
721
-		self::registerEncryptionWrapper();
722
-		self::registerEncryptionHooks();
723
-		self::registerAccountHooks();
724
-
725
-		// Make sure that the application class is not loaded before the database is setup
726
-		if ($systemConfig->getValue("installed", false)) {
727
-			$settings = new \OC\Settings\Application();
728
-			$settings->register();
729
-		}
730
-
731
-		//make sure temporary files are cleaned up
732
-		$tmpManager = \OC::$server->getTempManager();
733
-		register_shutdown_function(array($tmpManager, 'clean'));
734
-		$lockProvider = \OC::$server->getLockingProvider();
735
-		register_shutdown_function(array($lockProvider, 'releaseAll'));
736
-
737
-		// Check whether the sample configuration has been copied
738
-		if($systemConfig->getValue('copied_sample_config', false)) {
739
-			$l = \OC::$server->getL10N('lib');
740
-			header('HTTP/1.1 503 Service Temporarily Unavailable');
741
-			header('Status: 503 Service Temporarily Unavailable');
742
-			OC_Template::printErrorPage(
743
-				$l->t('Sample configuration detected'),
744
-				$l->t('It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php')
745
-			);
746
-			return;
747
-		}
748
-
749
-		$request = \OC::$server->getRequest();
750
-		$host = $request->getInsecureServerHost();
751
-		/**
752
-		 * if the host passed in headers isn't trusted
753
-		 * FIXME: Should not be in here at all :see_no_evil:
754
-		 */
755
-		if (!OC::$CLI
756
-			// overwritehost is always trusted, workaround to not have to make
757
-			// \OC\AppFramework\Http\Request::getOverwriteHost public
758
-			&& self::$server->getConfig()->getSystemValue('overwritehost') === ''
759
-			&& !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host)
760
-			&& self::$server->getConfig()->getSystemValue('installed', false)
761
-		) {
762
-			// Allow access to CSS resources
763
-			$isScssRequest = false;
764
-			if(strpos($request->getPathInfo(), '/css/') === 0) {
765
-				$isScssRequest = true;
766
-			}
767
-
768
-			if(substr($request->getRequestUri(), -11) === '/status.php') {
769
-				OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
770
-				header('Status: 400 Bad Request');
771
-				header('Content-Type: application/json');
772
-				echo '{"error": "Trusted domain error.", "code": 15}';
773
-				exit();
774
-			}
775
-
776
-			if (!$isScssRequest) {
777
-				OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
778
-				header('Status: 400 Bad Request');
779
-
780
-				\OC::$server->getLogger()->warning(
781
-					'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.',
782
-					[
783
-						'app' => 'core',
784
-						'remoteAddress' => $request->getRemoteAddress(),
785
-						'host' => $host,
786
-					]
787
-				);
788
-
789
-				$tmpl = new OCP\Template('core', 'untrustedDomain', 'guest');
790
-				$tmpl->assign('domain', $host);
791
-				$tmpl->printPage();
792
-
793
-				exit();
794
-			}
795
-		}
796
-		\OC::$server->getEventLogger()->end('boot');
797
-	}
798
-
799
-	/**
800
-	 * register hooks for the cleanup of cache and bruteforce protection
801
-	 */
802
-	public static function registerCleanupHooks() {
803
-		//don't try to do this before we are properly setup
804
-		if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
805
-
806
-			// NOTE: This will be replaced to use OCP
807
-			$userSession = self::$server->getUserSession();
808
-			$userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
809
-				if (!defined('PHPUNIT_RUN')) {
810
-					// reset brute force delay for this IP address and username
811
-					$uid = \OC::$server->getUserSession()->getUser()->getUID();
812
-					$request = \OC::$server->getRequest();
813
-					$throttler = \OC::$server->getBruteForceThrottler();
814
-					$throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
815
-				}
816
-
817
-				try {
818
-					$cache = new \OC\Cache\File();
819
-					$cache->gc();
820
-				} catch (\OC\ServerNotAvailableException $e) {
821
-					// not a GC exception, pass it on
822
-					throw $e;
823
-				} catch (\OC\ForbiddenException $e) {
824
-					// filesystem blocked for this request, ignore
825
-				} catch (\Exception $e) {
826
-					// a GC exception should not prevent users from using OC,
827
-					// so log the exception
828
-					\OC::$server->getLogger()->logException($e, [
829
-						'message' => 'Exception when running cache gc.',
830
-						'level' => \OCP\Util::WARN,
831
-						'app' => 'core',
832
-					]);
833
-				}
834
-			});
835
-		}
836
-	}
837
-
838
-	private static function registerEncryptionWrapper() {
839
-		$manager = self::$server->getEncryptionManager();
840
-		\OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
841
-	}
842
-
843
-	private static function registerEncryptionHooks() {
844
-		$enabled = self::$server->getEncryptionManager()->isEnabled();
845
-		if ($enabled) {
846
-			\OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared');
847
-			\OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared');
848
-			\OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename');
849
-			\OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore');
850
-		}
851
-	}
852
-
853
-	private static function registerAccountHooks() {
854
-		$hookHandler = new \OC\Accounts\Hooks(\OC::$server->getLogger());
855
-		\OCP\Util::connectHook('OC_User', 'changeUser', $hookHandler, 'changeUserHook');
856
-	}
857
-
858
-	/**
859
-	 * register hooks for the filesystem
860
-	 */
861
-	public static function registerFilesystemHooks() {
862
-		// Check for blacklisted files
863
-		OC_Hook::connect('OC_Filesystem', 'write', Filesystem::class, 'isBlacklisted');
864
-		OC_Hook::connect('OC_Filesystem', 'rename', Filesystem::class, 'isBlacklisted');
865
-	}
866
-
867
-	/**
868
-	 * register hooks for sharing
869
-	 */
870
-	public static function registerShareHooks() {
871
-		if (\OC::$server->getSystemConfig()->getValue('installed')) {
872
-			OC_Hook::connect('OC_User', 'post_deleteUser', Hooks::class, 'post_deleteUser');
873
-			OC_Hook::connect('OC_User', 'post_removeFromGroup', Hooks::class, 'post_removeFromGroup');
874
-			OC_Hook::connect('OC_User', 'post_deleteGroup', Hooks::class, 'post_deleteGroup');
875
-		}
876
-	}
877
-
878
-	protected static function registerAutoloaderCache() {
879
-		// The class loader takes an optional low-latency cache, which MUST be
880
-		// namespaced. The instanceid is used for namespacing, but might be
881
-		// unavailable at this point. Furthermore, it might not be possible to
882
-		// generate an instanceid via \OC_Util::getInstanceId() because the
883
-		// config file may not be writable. As such, we only register a class
884
-		// loader cache if instanceid is available without trying to create one.
885
-		$instanceId = \OC::$server->getSystemConfig()->getValue('instanceid', null);
886
-		if ($instanceId) {
887
-			try {
888
-				$memcacheFactory = \OC::$server->getMemCacheFactory();
889
-				self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
890
-			} catch (\Exception $ex) {
891
-			}
892
-		}
893
-	}
894
-
895
-	/**
896
-	 * Handle the request
897
-	 */
898
-	public static function handleRequest() {
899
-
900
-		\OC::$server->getEventLogger()->start('handle_request', 'Handle request');
901
-		$systemConfig = \OC::$server->getSystemConfig();
902
-		// load all the classpaths from the enabled apps so they are available
903
-		// in the routing files of each app
904
-		OC::loadAppClassPaths();
905
-
906
-		// Check if Nextcloud is installed or in maintenance (update) mode
907
-		if (!$systemConfig->getValue('installed', false)) {
908
-			\OC::$server->getSession()->clear();
909
-			$setupHelper = new OC\Setup(
910
-				$systemConfig,
911
-				\OC::$server->getIniWrapper(),
912
-				\OC::$server->getL10N('lib'),
913
-				\OC::$server->query(\OCP\Defaults::class),
914
-				\OC::$server->getLogger(),
915
-				\OC::$server->getSecureRandom(),
916
-				\OC::$server->query(\OC\Installer::class)
917
-			);
918
-			$controller = new OC\Core\Controller\SetupController($setupHelper);
919
-			$controller->run($_POST);
920
-			exit();
921
-		}
922
-
923
-		$request = \OC::$server->getRequest();
924
-		$requestPath = $request->getRawPathInfo();
925
-		if ($requestPath === '/heartbeat') {
926
-			return;
927
-		}
928
-		if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade
929
-			self::checkMaintenanceMode();
930
-
931
-			if (\OCP\Util::needUpgrade()) {
932
-				if (function_exists('opcache_reset')) {
933
-					opcache_reset();
934
-				}
935
-				if (!$systemConfig->getValue('maintenance', false)) {
936
-					self::printUpgradePage($systemConfig);
937
-					exit();
938
-				}
939
-			}
940
-		}
941
-
942
-		// emergency app disabling
943
-		if ($requestPath === '/disableapp'
944
-			&& $request->getMethod() === 'POST'
945
-			&& ((array)$request->getParam('appid')) !== ''
946
-		) {
947
-			\OCP\JSON::callCheck();
948
-			\OCP\JSON::checkAdminUser();
949
-			$appIds = (array)$request->getParam('appid');
950
-			foreach($appIds as $appId) {
951
-				$appId = \OC_App::cleanAppId($appId);
952
-				\OC::$server->getAppManager()->disableApp($appId);
953
-			}
954
-			\OC_JSON::success();
955
-			exit();
956
-		}
957
-
958
-		// Always load authentication apps
959
-		OC_App::loadApps(['authentication']);
960
-
961
-		// Load minimum set of apps
962
-		if (!\OCP\Util::needUpgrade()
963
-			&& !$systemConfig->getValue('maintenance', false)) {
964
-			// For logged-in users: Load everything
965
-			if(\OC::$server->getUserSession()->isLoggedIn()) {
966
-				OC_App::loadApps();
967
-			} else {
968
-				// For guests: Load only filesystem and logging
969
-				OC_App::loadApps(array('filesystem', 'logging'));
970
-				self::handleLogin($request);
971
-			}
972
-		}
973
-
974
-		if (!self::$CLI) {
975
-			try {
976
-				if (!$systemConfig->getValue('maintenance', false) && !\OCP\Util::needUpgrade()) {
977
-					OC_App::loadApps(array('filesystem', 'logging'));
978
-					OC_App::loadApps();
979
-				}
980
-				OC_Util::setupFS();
981
-				OC::$server->getRouter()->match(\OC::$server->getRequest()->getRawPathInfo());
982
-				return;
983
-			} catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
984
-				//header('HTTP/1.0 404 Not Found');
985
-			} catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
986
-				OC_Response::setStatus(405);
987
-				return;
988
-			}
989
-		}
990
-
991
-		// Handle WebDAV
992
-		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
993
-			// not allowed any more to prevent people
994
-			// mounting this root directly.
995
-			// Users need to mount remote.php/webdav instead.
996
-			header('HTTP/1.1 405 Method Not Allowed');
997
-			header('Status: 405 Method Not Allowed');
998
-			return;
999
-		}
1000
-
1001
-		// Someone is logged in
1002
-		if (\OC::$server->getUserSession()->isLoggedIn()) {
1003
-			OC_App::loadApps();
1004
-			OC_User::setupBackends();
1005
-			OC_Util::setupFS();
1006
-			// FIXME
1007
-			// Redirect to default application
1008
-			OC_Util::redirectToDefaultPage();
1009
-		} else {
1010
-			// Not handled and not logged in
1011
-			header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
1012
-		}
1013
-	}
1014
-
1015
-	/**
1016
-	 * Check login: apache auth, auth token, basic auth
1017
-	 *
1018
-	 * @param OCP\IRequest $request
1019
-	 * @return boolean
1020
-	 */
1021
-	static function handleLogin(OCP\IRequest $request) {
1022
-		$userSession = self::$server->getUserSession();
1023
-		if (OC_User::handleApacheAuth()) {
1024
-			return true;
1025
-		}
1026
-		if ($userSession->tryTokenLogin($request)) {
1027
-			return true;
1028
-		}
1029
-		if (isset($_COOKIE['nc_username'])
1030
-			&& isset($_COOKIE['nc_token'])
1031
-			&& isset($_COOKIE['nc_session_id'])
1032
-			&& $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
1033
-			return true;
1034
-		}
1035
-		if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
1036
-			return true;
1037
-		}
1038
-		return false;
1039
-	}
1040
-
1041
-	protected static function handleAuthHeaders() {
1042
-		//copy http auth headers for apache+php-fcgid work around
1043
-		if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
1044
-			$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
1045
-		}
1046
-
1047
-		// Extract PHP_AUTH_USER/PHP_AUTH_PW from other headers if necessary.
1048
-		$vars = array(
1049
-			'HTTP_AUTHORIZATION', // apache+php-cgi work around
1050
-			'REDIRECT_HTTP_AUTHORIZATION', // apache+php-cgi alternative
1051
-		);
1052
-		foreach ($vars as $var) {
1053
-			if (isset($_SERVER[$var]) && preg_match('/Basic\s+(.*)$/i', $_SERVER[$var], $matches)) {
1054
-				list($name, $password) = explode(':', base64_decode($matches[1]), 2);
1055
-				$_SERVER['PHP_AUTH_USER'] = $name;
1056
-				$_SERVER['PHP_AUTH_PW'] = $password;
1057
-				break;
1058
-			}
1059
-		}
1060
-	}
70
+    /**
71
+     * Associative array for autoloading. classname => filename
72
+     */
73
+    public static $CLASSPATH = array();
74
+    /**
75
+     * The installation path for Nextcloud  on the server (e.g. /srv/http/nextcloud)
76
+     */
77
+    public static $SERVERROOT = '';
78
+    /**
79
+     * the current request path relative to the Nextcloud root (e.g. files/index.php)
80
+     */
81
+    private static $SUBURI = '';
82
+    /**
83
+     * the Nextcloud root path for http requests (e.g. nextcloud/)
84
+     */
85
+    public static $WEBROOT = '';
86
+    /**
87
+     * The installation path array of the apps folder on the server (e.g. /srv/http/nextcloud) 'path' and
88
+     * web path in 'url'
89
+     */
90
+    public static $APPSROOTS = array();
91
+
92
+    /**
93
+     * @var string
94
+     */
95
+    public static $configDir;
96
+
97
+    /**
98
+     * requested app
99
+     */
100
+    public static $REQUESTEDAPP = '';
101
+
102
+    /**
103
+     * check if Nextcloud runs in cli mode
104
+     */
105
+    public static $CLI = false;
106
+
107
+    /**
108
+     * @var \OC\Autoloader $loader
109
+     */
110
+    public static $loader = null;
111
+
112
+    /** @var \Composer\Autoload\ClassLoader $composerAutoloader */
113
+    public static $composerAutoloader = null;
114
+
115
+    /**
116
+     * @var \OC\Server
117
+     */
118
+    public static $server = null;
119
+
120
+    /**
121
+     * @var \OC\Config
122
+     */
123
+    private static $config = null;
124
+
125
+    /**
126
+     * @throws \RuntimeException when the 3rdparty directory is missing or
127
+     * the app path list is empty or contains an invalid path
128
+     */
129
+    public static function initPaths() {
130
+        if(defined('PHPUNIT_CONFIG_DIR')) {
131
+            self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
132
+        } elseif(defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) {
133
+            self::$configDir = OC::$SERVERROOT . '/tests/config/';
134
+        } elseif($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
135
+            self::$configDir = rtrim($dir, '/') . '/';
136
+        } else {
137
+            self::$configDir = OC::$SERVERROOT . '/config/';
138
+        }
139
+        self::$config = new \OC\Config(self::$configDir);
140
+
141
+        OC::$SUBURI = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen(OC::$SERVERROOT)));
142
+        /**
143
+         * FIXME: The following lines are required because we can't yet instantiate
144
+         *        \OC::$server->getRequest() since \OC::$server does not yet exist.
145
+         */
146
+        $params = [
147
+            'server' => [
148
+                'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
149
+                'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
150
+            ],
151
+        ];
152
+        $fakeRequest = new \OC\AppFramework\Http\Request($params, null, new \OC\AllConfig(new \OC\SystemConfig(self::$config)));
153
+        $scriptName = $fakeRequest->getScriptName();
154
+        if (substr($scriptName, -1) == '/') {
155
+            $scriptName .= 'index.php';
156
+            //make sure suburi follows the same rules as scriptName
157
+            if (substr(OC::$SUBURI, -9) != 'index.php') {
158
+                if (substr(OC::$SUBURI, -1) != '/') {
159
+                    OC::$SUBURI = OC::$SUBURI . '/';
160
+                }
161
+                OC::$SUBURI = OC::$SUBURI . 'index.php';
162
+            }
163
+        }
164
+
165
+
166
+        if (OC::$CLI) {
167
+            OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
168
+        } else {
169
+            if (substr($scriptName, 0 - strlen(OC::$SUBURI)) === OC::$SUBURI) {
170
+                OC::$WEBROOT = substr($scriptName, 0, 0 - strlen(OC::$SUBURI));
171
+
172
+                if (OC::$WEBROOT != '' && OC::$WEBROOT[0] !== '/') {
173
+                    OC::$WEBROOT = '/' . OC::$WEBROOT;
174
+                }
175
+            } else {
176
+                // The scriptName is not ending with OC::$SUBURI
177
+                // This most likely means that we are calling from CLI.
178
+                // However some cron jobs still need to generate
179
+                // a web URL, so we use overwritewebroot as a fallback.
180
+                OC::$WEBROOT = self::$config->getValue('overwritewebroot', '');
181
+            }
182
+
183
+            // Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
184
+            // slash which is required by URL generation.
185
+            if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
186
+                    substr($_SERVER['REQUEST_URI'], -1) !== '/') {
187
+                header('Location: '.\OC::$WEBROOT.'/');
188
+                exit();
189
+            }
190
+        }
191
+
192
+        // search the apps folder
193
+        $config_paths = self::$config->getValue('apps_paths', array());
194
+        if (!empty($config_paths)) {
195
+            foreach ($config_paths as $paths) {
196
+                if (isset($paths['url']) && isset($paths['path'])) {
197
+                    $paths['url'] = rtrim($paths['url'], '/');
198
+                    $paths['path'] = rtrim($paths['path'], '/');
199
+                    OC::$APPSROOTS[] = $paths;
200
+                }
201
+            }
202
+        } elseif (file_exists(OC::$SERVERROOT . '/apps')) {
203
+            OC::$APPSROOTS[] = array('path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true);
204
+        } elseif (file_exists(OC::$SERVERROOT . '/../apps')) {
205
+            OC::$APPSROOTS[] = array(
206
+                'path' => rtrim(dirname(OC::$SERVERROOT), '/') . '/apps',
207
+                'url' => '/apps',
208
+                'writable' => true
209
+            );
210
+        }
211
+
212
+        if (empty(OC::$APPSROOTS)) {
213
+            throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
214
+                . ' or the folder above. You can also configure the location in the config.php file.');
215
+        }
216
+        $paths = array();
217
+        foreach (OC::$APPSROOTS as $path) {
218
+            $paths[] = $path['path'];
219
+            if (!is_dir($path['path'])) {
220
+                throw new \RuntimeException(sprintf('App directory "%s" not found! Please put the Nextcloud apps folder in the'
221
+                    . ' Nextcloud folder or the folder above. You can also configure the location in the'
222
+                    . ' config.php file.', $path['path']));
223
+            }
224
+        }
225
+
226
+        // set the right include path
227
+        set_include_path(
228
+            implode(PATH_SEPARATOR, $paths)
229
+        );
230
+    }
231
+
232
+    public static function checkConfig() {
233
+        $l = \OC::$server->getL10N('lib');
234
+
235
+        // Create config if it does not already exist
236
+        $configFilePath = self::$configDir .'/config.php';
237
+        if(!file_exists($configFilePath)) {
238
+            @touch($configFilePath);
239
+        }
240
+
241
+        // Check if config is writable
242
+        $configFileWritable = is_writable($configFilePath);
243
+        if (!$configFileWritable && !OC_Helper::isReadOnlyConfigEnabled()
244
+            || !$configFileWritable && \OCP\Util::needUpgrade()) {
245
+
246
+            $urlGenerator = \OC::$server->getURLGenerator();
247
+
248
+            if (self::$CLI) {
249
+                echo $l->t('Cannot write into "config" directory!')."\n";
250
+                echo $l->t('This can usually be fixed by giving the webserver write access to the config directory')."\n";
251
+                echo "\n";
252
+                echo $l->t('See %s', [ $urlGenerator->linkToDocs('admin-dir_permissions') ])."\n";
253
+                exit;
254
+            } else {
255
+                OC_Template::printErrorPage(
256
+                    $l->t('Cannot write into "config" directory!'),
257
+                    $l->t('This can usually be fixed by giving the webserver write access to the config directory. See %s',
258
+                        [ $urlGenerator->linkToDocs('admin-dir_permissions') ])
259
+                );
260
+            }
261
+        }
262
+    }
263
+
264
+    public static function checkInstalled() {
265
+        if (defined('OC_CONSOLE')) {
266
+            return;
267
+        }
268
+        // Redirect to installer if not installed
269
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false) && OC::$SUBURI !== '/index.php' && OC::$SUBURI !== '/status.php') {
270
+            if (OC::$CLI) {
271
+                throw new Exception('Not installed');
272
+            } else {
273
+                $url = OC::$WEBROOT . '/index.php';
274
+                header('Location: ' . $url);
275
+            }
276
+            exit();
277
+        }
278
+    }
279
+
280
+    public static function checkMaintenanceMode() {
281
+        // Allow ajax update script to execute without being stopped
282
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false) && OC::$SUBURI != '/core/ajax/update.php') {
283
+            // send http status 503
284
+            header('HTTP/1.1 503 Service Temporarily Unavailable');
285
+            header('Status: 503 Service Temporarily Unavailable');
286
+            header('Retry-After: 120');
287
+
288
+            // render error page
289
+            $template = new OC_Template('', 'update.user', 'guest');
290
+            OC_Util::addScript('maintenance-check');
291
+            OC_Util::addStyle('core', 'guest');
292
+            $template->printPage();
293
+            die();
294
+        }
295
+    }
296
+
297
+    /**
298
+     * Prints the upgrade page
299
+     *
300
+     * @param \OC\SystemConfig $systemConfig
301
+     */
302
+    private static function printUpgradePage(\OC\SystemConfig $systemConfig) {
303
+        $disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false);
304
+        $tooBig = false;
305
+        if (!$disableWebUpdater) {
306
+            $apps = \OC::$server->getAppManager();
307
+            if ($apps->isInstalled('user_ldap')) {
308
+                $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
309
+
310
+                $result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
311
+                    ->from('ldap_user_mapping')
312
+                    ->execute();
313
+                $row = $result->fetch();
314
+                $result->closeCursor();
315
+
316
+                $tooBig = ($row['user_count'] > 50);
317
+            }
318
+            if (!$tooBig && $apps->isInstalled('user_saml')) {
319
+                $qb = \OC::$server->getDatabaseConnection()->getQueryBuilder();
320
+
321
+                $result = $qb->selectAlias($qb->createFunction('COUNT(*)'), 'user_count')
322
+                    ->from('user_saml_users')
323
+                    ->execute();
324
+                $row = $result->fetch();
325
+                $result->closeCursor();
326
+
327
+                $tooBig = ($row['user_count'] > 50);
328
+            }
329
+            if (!$tooBig) {
330
+                // count users
331
+                $stats = \OC::$server->getUserManager()->countUsers();
332
+                $totalUsers = array_sum($stats);
333
+                $tooBig = ($totalUsers > 50);
334
+            }
335
+        }
336
+        $ignoreTooBigWarning = isset($_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup']) &&
337
+            $_GET['IKnowThatThisIsABigInstanceAndTheUpdateRequestCouldRunIntoATimeoutAndHowToRestoreABackup'] === 'IAmSuperSureToDoThis';
338
+
339
+        if ($disableWebUpdater || ($tooBig && !$ignoreTooBigWarning)) {
340
+            // send http status 503
341
+            header('HTTP/1.1 503 Service Temporarily Unavailable');
342
+            header('Status: 503 Service Temporarily Unavailable');
343
+            header('Retry-After: 120');
344
+
345
+            // render error page
346
+            $template = new OC_Template('', 'update.use-cli', 'guest');
347
+            $template->assign('productName', 'nextcloud'); // for now
348
+            $template->assign('version', OC_Util::getVersionString());
349
+            $template->assign('tooBig', $tooBig);
350
+
351
+            $template->printPage();
352
+            die();
353
+        }
354
+
355
+        // check whether this is a core update or apps update
356
+        $installedVersion = $systemConfig->getValue('version', '0.0.0');
357
+        $currentVersion = implode('.', \OCP\Util::getVersion());
358
+
359
+        // if not a core upgrade, then it's apps upgrade
360
+        $isAppsOnlyUpgrade = version_compare($currentVersion, $installedVersion, '=');
361
+
362
+        $oldTheme = $systemConfig->getValue('theme');
363
+        $systemConfig->setValue('theme', '');
364
+        OC_Util::addScript('config'); // needed for web root
365
+        OC_Util::addScript('update');
366
+
367
+        /** @var \OC\App\AppManager $appManager */
368
+        $appManager = \OC::$server->getAppManager();
369
+
370
+        $tmpl = new OC_Template('', 'update.admin', 'guest');
371
+        $tmpl->assign('version', OC_Util::getVersionString());
372
+        $tmpl->assign('isAppsOnlyUpgrade', $isAppsOnlyUpgrade);
373
+
374
+        // get third party apps
375
+        $ocVersion = \OCP\Util::getVersion();
376
+        $ocVersion = implode('.', $ocVersion);
377
+        $incompatibleApps = $appManager->getIncompatibleApps($ocVersion);
378
+        $incompatibleShippedApps = [];
379
+        foreach ($incompatibleApps as $appInfo) {
380
+            if ($appManager->isShipped($appInfo['id'])) {
381
+                $incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')';
382
+            }
383
+        }
384
+
385
+        if (!empty($incompatibleShippedApps)) {
386
+            $l = \OC::$server->getL10N('core');
387
+            $hint = $l->t('The files of the app %$1s were not replaced correctly. Make sure it is a version compatible with the server.', [implode(', ', $incompatibleShippedApps)]);
388
+            throw new \OC\HintException('The files of the app ' . implode(', ', $incompatibleShippedApps) . ' were not replaced correctly. Make sure it is a version compatible with the server.', $hint);
389
+        }
390
+
391
+        $tmpl->assign('appsToUpgrade', $appManager->getAppsNeedingUpgrade($ocVersion));
392
+        $tmpl->assign('incompatibleAppsList', $incompatibleApps);
393
+        $tmpl->assign('productName', 'Nextcloud'); // for now
394
+        $tmpl->assign('oldTheme', $oldTheme);
395
+        $tmpl->printPage();
396
+    }
397
+
398
+    public static function initSession() {
399
+        if(self::$server->getRequest()->getServerProtocol() === 'https') {
400
+            ini_set('session.cookie_secure', true);
401
+        }
402
+
403
+        // prevents javascript from accessing php session cookies
404
+        ini_set('session.cookie_httponly', 'true');
405
+
406
+        // set the cookie path to the Nextcloud directory
407
+        $cookie_path = OC::$WEBROOT ? : '/';
408
+        ini_set('session.cookie_path', $cookie_path);
409
+
410
+        // Let the session name be changed in the initSession Hook
411
+        $sessionName = OC_Util::getInstanceId();
412
+
413
+        try {
414
+            // Allow session apps to create a custom session object
415
+            $useCustomSession = false;
416
+            $session = self::$server->getSession();
417
+            OC_Hook::emit('OC', 'initSession', array('session' => &$session, 'sessionName' => &$sessionName, 'useCustomSession' => &$useCustomSession));
418
+            if (!$useCustomSession) {
419
+                // set the session name to the instance id - which is unique
420
+                $session = new \OC\Session\Internal($sessionName);
421
+            }
422
+
423
+            $cryptoWrapper = \OC::$server->getSessionCryptoWrapper();
424
+            $session = $cryptoWrapper->wrapSession($session);
425
+            self::$server->setSession($session);
426
+
427
+            // if session can't be started break with http 500 error
428
+        } catch (Exception $e) {
429
+            \OC::$server->getLogger()->logException($e, ['app' => 'base']);
430
+            //show the user a detailed error page
431
+            OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR);
432
+            OC_Template::printExceptionErrorPage($e);
433
+            die();
434
+        }
435
+
436
+        $sessionLifeTime = self::getSessionLifeTime();
437
+
438
+        // session timeout
439
+        if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
440
+            if (isset($_COOKIE[session_name()])) {
441
+                setcookie(session_name(), null, -1, self::$WEBROOT ? : '/');
442
+            }
443
+            \OC::$server->getUserSession()->logout();
444
+        }
445
+
446
+        $session->set('LAST_ACTIVITY', time());
447
+    }
448
+
449
+    /**
450
+     * @return string
451
+     */
452
+    private static function getSessionLifeTime() {
453
+        return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
454
+    }
455
+
456
+    public static function loadAppClassPaths() {
457
+        foreach (OC_App::getEnabledApps() as $app) {
458
+            $appPath = OC_App::getAppPath($app);
459
+            if ($appPath === false) {
460
+                continue;
461
+            }
462
+
463
+            $file = $appPath . '/appinfo/classpath.php';
464
+            if (file_exists($file)) {
465
+                require_once $file;
466
+            }
467
+        }
468
+    }
469
+
470
+    /**
471
+     * Try to set some values to the required Nextcloud default
472
+     */
473
+    public static function setRequiredIniValues() {
474
+        @ini_set('default_charset', 'UTF-8');
475
+        @ini_set('gd.jpeg_ignore_warning', '1');
476
+    }
477
+
478
+    /**
479
+     * Send the same site cookies
480
+     */
481
+    private static function sendSameSiteCookies() {
482
+        $cookieParams = session_get_cookie_params();
483
+        $secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
484
+        $policies = [
485
+            'lax',
486
+            'strict',
487
+        ];
488
+
489
+        // Append __Host to the cookie if it meets the requirements
490
+        $cookiePrefix = '';
491
+        if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
492
+            $cookiePrefix = '__Host-';
493
+        }
494
+
495
+        foreach($policies as $policy) {
496
+            header(
497
+                sprintf(
498
+                    'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
499
+                    $cookiePrefix,
500
+                    $policy,
501
+                    $cookieParams['path'],
502
+                    $policy
503
+                ),
504
+                false
505
+            );
506
+        }
507
+    }
508
+
509
+    /**
510
+     * Same Site cookie to further mitigate CSRF attacks. This cookie has to
511
+     * be set in every request if cookies are sent to add a second level of
512
+     * defense against CSRF.
513
+     *
514
+     * If the cookie is not sent this will set the cookie and reload the page.
515
+     * We use an additional cookie since we want to protect logout CSRF and
516
+     * also we can't directly interfere with PHP's session mechanism.
517
+     */
518
+    private static function performSameSiteCookieProtection() {
519
+        $request = \OC::$server->getRequest();
520
+
521
+        // Some user agents are notorious and don't really properly follow HTTP
522
+        // specifications. For those, have an automated opt-out. Since the protection
523
+        // for remote.php is applied in base.php as starting point we need to opt out
524
+        // here.
525
+        $incompatibleUserAgents = [
526
+            // OS X Finder
527
+            '/^WebDAVFS/',
528
+        ];
529
+        if($request->isUserAgent($incompatibleUserAgents)) {
530
+            return;
531
+        }
532
+
533
+        if(count($_COOKIE) > 0) {
534
+            $requestUri = $request->getScriptName();
535
+            $processingScript = explode('/', $requestUri);
536
+            $processingScript = $processingScript[count($processingScript)-1];
537
+
538
+            // index.php routes are handled in the middleware
539
+            if($processingScript === 'index.php') {
540
+                return;
541
+            }
542
+
543
+            // All other endpoints require the lax and the strict cookie
544
+            if(!$request->passesStrictCookieCheck()) {
545
+                self::sendSameSiteCookies();
546
+                // Debug mode gets access to the resources without strict cookie
547
+                // due to the fact that the SabreDAV browser also lives there.
548
+                if(!\OC::$server->getConfig()->getSystemValue('debug', false)) {
549
+                    http_response_code(\OCP\AppFramework\Http::STATUS_SERVICE_UNAVAILABLE);
550
+                    exit();
551
+                }
552
+            }
553
+        } elseif(!isset($_COOKIE['nc_sameSiteCookielax']) || !isset($_COOKIE['nc_sameSiteCookiestrict'])) {
554
+            self::sendSameSiteCookies();
555
+        }
556
+    }
557
+
558
+    public static function init() {
559
+        // calculate the root directories
560
+        OC::$SERVERROOT = str_replace("\\", '/', substr(__DIR__, 0, -4));
561
+
562
+        // register autoloader
563
+        $loaderStart = microtime(true);
564
+        require_once __DIR__ . '/autoloader.php';
565
+        self::$loader = new \OC\Autoloader([
566
+            OC::$SERVERROOT . '/lib/private/legacy',
567
+        ]);
568
+        if (defined('PHPUNIT_RUN')) {
569
+            self::$loader->addValidRoot(OC::$SERVERROOT . '/tests');
570
+        }
571
+        spl_autoload_register(array(self::$loader, 'load'));
572
+        $loaderEnd = microtime(true);
573
+
574
+        self::$CLI = (php_sapi_name() == 'cli');
575
+
576
+        // Add default composer PSR-4 autoloader
577
+        self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
578
+
579
+        try {
580
+            self::initPaths();
581
+            // setup 3rdparty autoloader
582
+            $vendorAutoLoad = OC::$SERVERROOT. '/3rdparty/autoload.php';
583
+            if (!file_exists($vendorAutoLoad)) {
584
+                throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
585
+            }
586
+            require_once $vendorAutoLoad;
587
+
588
+        } catch (\RuntimeException $e) {
589
+            if (!self::$CLI) {
590
+                $claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
591
+                $protocol = in_array($claimedProtocol, ['HTTP/1.0', 'HTTP/1.1', 'HTTP/2']) ? $claimedProtocol : 'HTTP/1.1';
592
+                header($protocol . ' ' . OC_Response::STATUS_SERVICE_UNAVAILABLE);
593
+            }
594
+            // we can't use the template error page here, because this needs the
595
+            // DI container which isn't available yet
596
+            print($e->getMessage());
597
+            exit();
598
+        }
599
+
600
+        // setup the basic server
601
+        self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
602
+        \OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
603
+        \OC::$server->getEventLogger()->start('boot', 'Initialize');
604
+
605
+        // Don't display errors and log them
606
+        error_reporting(E_ALL | E_STRICT);
607
+        @ini_set('display_errors', '0');
608
+        @ini_set('log_errors', '1');
609
+
610
+        if(!date_default_timezone_set('UTC')) {
611
+            throw new \RuntimeException('Could not set timezone to UTC');
612
+        }
613
+
614
+        //try to configure php to enable big file uploads.
615
+        //this doesn´t work always depending on the webserver and php configuration.
616
+        //Let´s try to overwrite some defaults anyway
617
+
618
+        //try to set the maximum execution time to 60min
619
+        if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
620
+            @set_time_limit(3600);
621
+        }
622
+        @ini_set('max_execution_time', '3600');
623
+        @ini_set('max_input_time', '3600');
624
+
625
+        //try to set the maximum filesize to 10G
626
+        @ini_set('upload_max_filesize', '10G');
627
+        @ini_set('post_max_size', '10G');
628
+        @ini_set('file_uploads', '50');
629
+
630
+        self::setRequiredIniValues();
631
+        self::handleAuthHeaders();
632
+        self::registerAutoloaderCache();
633
+
634
+        // initialize intl fallback is necessary
635
+        \Patchwork\Utf8\Bootup::initIntl();
636
+        OC_Util::isSetLocaleWorking();
637
+
638
+        if (!defined('PHPUNIT_RUN')) {
639
+            OC\Log\ErrorHandler::setLogger(\OC::$server->getLogger());
640
+            $debug = \OC::$server->getConfig()->getSystemValue('debug', false);
641
+            OC\Log\ErrorHandler::register($debug);
642
+        }
643
+
644
+        \OC::$server->getEventLogger()->start('init_session', 'Initialize session');
645
+        OC_App::loadApps(array('session'));
646
+        if (!self::$CLI) {
647
+            self::initSession();
648
+        }
649
+        \OC::$server->getEventLogger()->end('init_session');
650
+        self::checkConfig();
651
+        self::checkInstalled();
652
+
653
+        OC_Response::addSecurityHeaders();
654
+
655
+        self::performSameSiteCookieProtection();
656
+
657
+        if (!defined('OC_CONSOLE')) {
658
+            $errors = OC_Util::checkServer(\OC::$server->getSystemConfig());
659
+            if (count($errors) > 0) {
660
+                if (self::$CLI) {
661
+                    // Convert l10n string into regular string for usage in database
662
+                    $staticErrors = [];
663
+                    foreach ($errors as $error) {
664
+                        echo $error['error'] . "\n";
665
+                        echo $error['hint'] . "\n\n";
666
+                        $staticErrors[] = [
667
+                            'error' => (string)$error['error'],
668
+                            'hint' => (string)$error['hint'],
669
+                        ];
670
+                    }
671
+
672
+                    try {
673
+                        \OC::$server->getConfig()->setAppValue('core', 'cronErrors', json_encode($staticErrors));
674
+                    } catch (\Exception $e) {
675
+                        echo('Writing to database failed');
676
+                    }
677
+                    exit(1);
678
+                } else {
679
+                    OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
680
+                    OC_Util::addStyle('guest');
681
+                    OC_Template::printGuestPage('', 'error', array('errors' => $errors));
682
+                    exit;
683
+                }
684
+            } elseif (self::$CLI && \OC::$server->getConfig()->getSystemValue('installed', false)) {
685
+                \OC::$server->getConfig()->deleteAppValue('core', 'cronErrors');
686
+            }
687
+        }
688
+        //try to set the session lifetime
689
+        $sessionLifeTime = self::getSessionLifeTime();
690
+        @ini_set('gc_maxlifetime', (string)$sessionLifeTime);
691
+
692
+        $systemConfig = \OC::$server->getSystemConfig();
693
+
694
+        // User and Groups
695
+        if (!$systemConfig->getValue("installed", false)) {
696
+            self::$server->getSession()->set('user_id', '');
697
+        }
698
+
699
+        OC_User::useBackend(new \OC\User\Database());
700
+        \OC::$server->getGroupManager()->addBackend(new \OC\Group\Database());
701
+
702
+        // Subscribe to the hook
703
+        \OCP\Util::connectHook(
704
+            '\OCA\Files_Sharing\API\Server2Server',
705
+            'preLoginNameUsedAsUserName',
706
+            '\OC\User\Database',
707
+            'preLoginNameUsedAsUserName'
708
+        );
709
+
710
+        //setup extra user backends
711
+        if (!\OCP\Util::needUpgrade()) {
712
+            OC_User::setupBackends();
713
+        } else {
714
+            // Run upgrades in incognito mode
715
+            OC_User::setIncognitoMode(true);
716
+        }
717
+
718
+        self::registerCleanupHooks();
719
+        self::registerFilesystemHooks();
720
+        self::registerShareHooks();
721
+        self::registerEncryptionWrapper();
722
+        self::registerEncryptionHooks();
723
+        self::registerAccountHooks();
724
+
725
+        // Make sure that the application class is not loaded before the database is setup
726
+        if ($systemConfig->getValue("installed", false)) {
727
+            $settings = new \OC\Settings\Application();
728
+            $settings->register();
729
+        }
730
+
731
+        //make sure temporary files are cleaned up
732
+        $tmpManager = \OC::$server->getTempManager();
733
+        register_shutdown_function(array($tmpManager, 'clean'));
734
+        $lockProvider = \OC::$server->getLockingProvider();
735
+        register_shutdown_function(array($lockProvider, 'releaseAll'));
736
+
737
+        // Check whether the sample configuration has been copied
738
+        if($systemConfig->getValue('copied_sample_config', false)) {
739
+            $l = \OC::$server->getL10N('lib');
740
+            header('HTTP/1.1 503 Service Temporarily Unavailable');
741
+            header('Status: 503 Service Temporarily Unavailable');
742
+            OC_Template::printErrorPage(
743
+                $l->t('Sample configuration detected'),
744
+                $l->t('It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php')
745
+            );
746
+            return;
747
+        }
748
+
749
+        $request = \OC::$server->getRequest();
750
+        $host = $request->getInsecureServerHost();
751
+        /**
752
+         * if the host passed in headers isn't trusted
753
+         * FIXME: Should not be in here at all :see_no_evil:
754
+         */
755
+        if (!OC::$CLI
756
+            // overwritehost is always trusted, workaround to not have to make
757
+            // \OC\AppFramework\Http\Request::getOverwriteHost public
758
+            && self::$server->getConfig()->getSystemValue('overwritehost') === ''
759
+            && !\OC::$server->getTrustedDomainHelper()->isTrustedDomain($host)
760
+            && self::$server->getConfig()->getSystemValue('installed', false)
761
+        ) {
762
+            // Allow access to CSS resources
763
+            $isScssRequest = false;
764
+            if(strpos($request->getPathInfo(), '/css/') === 0) {
765
+                $isScssRequest = true;
766
+            }
767
+
768
+            if(substr($request->getRequestUri(), -11) === '/status.php') {
769
+                OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
770
+                header('Status: 400 Bad Request');
771
+                header('Content-Type: application/json');
772
+                echo '{"error": "Trusted domain error.", "code": 15}';
773
+                exit();
774
+            }
775
+
776
+            if (!$isScssRequest) {
777
+                OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
778
+                header('Status: 400 Bad Request');
779
+
780
+                \OC::$server->getLogger()->warning(
781
+                    'Trusted domain error. "{remoteAddress}" tried to access using "{host}" as host.',
782
+                    [
783
+                        'app' => 'core',
784
+                        'remoteAddress' => $request->getRemoteAddress(),
785
+                        'host' => $host,
786
+                    ]
787
+                );
788
+
789
+                $tmpl = new OCP\Template('core', 'untrustedDomain', 'guest');
790
+                $tmpl->assign('domain', $host);
791
+                $tmpl->printPage();
792
+
793
+                exit();
794
+            }
795
+        }
796
+        \OC::$server->getEventLogger()->end('boot');
797
+    }
798
+
799
+    /**
800
+     * register hooks for the cleanup of cache and bruteforce protection
801
+     */
802
+    public static function registerCleanupHooks() {
803
+        //don't try to do this before we are properly setup
804
+        if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
805
+
806
+            // NOTE: This will be replaced to use OCP
807
+            $userSession = self::$server->getUserSession();
808
+            $userSession->listen('\OC\User', 'postLogin', function () use ($userSession) {
809
+                if (!defined('PHPUNIT_RUN')) {
810
+                    // reset brute force delay for this IP address and username
811
+                    $uid = \OC::$server->getUserSession()->getUser()->getUID();
812
+                    $request = \OC::$server->getRequest();
813
+                    $throttler = \OC::$server->getBruteForceThrottler();
814
+                    $throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]);
815
+                }
816
+
817
+                try {
818
+                    $cache = new \OC\Cache\File();
819
+                    $cache->gc();
820
+                } catch (\OC\ServerNotAvailableException $e) {
821
+                    // not a GC exception, pass it on
822
+                    throw $e;
823
+                } catch (\OC\ForbiddenException $e) {
824
+                    // filesystem blocked for this request, ignore
825
+                } catch (\Exception $e) {
826
+                    // a GC exception should not prevent users from using OC,
827
+                    // so log the exception
828
+                    \OC::$server->getLogger()->logException($e, [
829
+                        'message' => 'Exception when running cache gc.',
830
+                        'level' => \OCP\Util::WARN,
831
+                        'app' => 'core',
832
+                    ]);
833
+                }
834
+            });
835
+        }
836
+    }
837
+
838
+    private static function registerEncryptionWrapper() {
839
+        $manager = self::$server->getEncryptionManager();
840
+        \OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorage');
841
+    }
842
+
843
+    private static function registerEncryptionHooks() {
844
+        $enabled = self::$server->getEncryptionManager()->isEnabled();
845
+        if ($enabled) {
846
+            \OCP\Util::connectHook(Share::class, 'post_shared', HookManager::class, 'postShared');
847
+            \OCP\Util::connectHook(Share::class, 'post_unshare', HookManager::class, 'postUnshared');
848
+            \OCP\Util::connectHook('OC_Filesystem', 'post_rename', HookManager::class, 'postRename');
849
+            \OCP\Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', HookManager::class, 'postRestore');
850
+        }
851
+    }
852
+
853
+    private static function registerAccountHooks() {
854
+        $hookHandler = new \OC\Accounts\Hooks(\OC::$server->getLogger());
855
+        \OCP\Util::connectHook('OC_User', 'changeUser', $hookHandler, 'changeUserHook');
856
+    }
857
+
858
+    /**
859
+     * register hooks for the filesystem
860
+     */
861
+    public static function registerFilesystemHooks() {
862
+        // Check for blacklisted files
863
+        OC_Hook::connect('OC_Filesystem', 'write', Filesystem::class, 'isBlacklisted');
864
+        OC_Hook::connect('OC_Filesystem', 'rename', Filesystem::class, 'isBlacklisted');
865
+    }
866
+
867
+    /**
868
+     * register hooks for sharing
869
+     */
870
+    public static function registerShareHooks() {
871
+        if (\OC::$server->getSystemConfig()->getValue('installed')) {
872
+            OC_Hook::connect('OC_User', 'post_deleteUser', Hooks::class, 'post_deleteUser');
873
+            OC_Hook::connect('OC_User', 'post_removeFromGroup', Hooks::class, 'post_removeFromGroup');
874
+            OC_Hook::connect('OC_User', 'post_deleteGroup', Hooks::class, 'post_deleteGroup');
875
+        }
876
+    }
877
+
878
+    protected static function registerAutoloaderCache() {
879
+        // The class loader takes an optional low-latency cache, which MUST be
880
+        // namespaced. The instanceid is used for namespacing, but might be
881
+        // unavailable at this point. Furthermore, it might not be possible to
882
+        // generate an instanceid via \OC_Util::getInstanceId() because the
883
+        // config file may not be writable. As such, we only register a class
884
+        // loader cache if instanceid is available without trying to create one.
885
+        $instanceId = \OC::$server->getSystemConfig()->getValue('instanceid', null);
886
+        if ($instanceId) {
887
+            try {
888
+                $memcacheFactory = \OC::$server->getMemCacheFactory();
889
+                self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
890
+            } catch (\Exception $ex) {
891
+            }
892
+        }
893
+    }
894
+
895
+    /**
896
+     * Handle the request
897
+     */
898
+    public static function handleRequest() {
899
+
900
+        \OC::$server->getEventLogger()->start('handle_request', 'Handle request');
901
+        $systemConfig = \OC::$server->getSystemConfig();
902
+        // load all the classpaths from the enabled apps so they are available
903
+        // in the routing files of each app
904
+        OC::loadAppClassPaths();
905
+
906
+        // Check if Nextcloud is installed or in maintenance (update) mode
907
+        if (!$systemConfig->getValue('installed', false)) {
908
+            \OC::$server->getSession()->clear();
909
+            $setupHelper = new OC\Setup(
910
+                $systemConfig,
911
+                \OC::$server->getIniWrapper(),
912
+                \OC::$server->getL10N('lib'),
913
+                \OC::$server->query(\OCP\Defaults::class),
914
+                \OC::$server->getLogger(),
915
+                \OC::$server->getSecureRandom(),
916
+                \OC::$server->query(\OC\Installer::class)
917
+            );
918
+            $controller = new OC\Core\Controller\SetupController($setupHelper);
919
+            $controller->run($_POST);
920
+            exit();
921
+        }
922
+
923
+        $request = \OC::$server->getRequest();
924
+        $requestPath = $request->getRawPathInfo();
925
+        if ($requestPath === '/heartbeat') {
926
+            return;
927
+        }
928
+        if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade
929
+            self::checkMaintenanceMode();
930
+
931
+            if (\OCP\Util::needUpgrade()) {
932
+                if (function_exists('opcache_reset')) {
933
+                    opcache_reset();
934
+                }
935
+                if (!$systemConfig->getValue('maintenance', false)) {
936
+                    self::printUpgradePage($systemConfig);
937
+                    exit();
938
+                }
939
+            }
940
+        }
941
+
942
+        // emergency app disabling
943
+        if ($requestPath === '/disableapp'
944
+            && $request->getMethod() === 'POST'
945
+            && ((array)$request->getParam('appid')) !== ''
946
+        ) {
947
+            \OCP\JSON::callCheck();
948
+            \OCP\JSON::checkAdminUser();
949
+            $appIds = (array)$request->getParam('appid');
950
+            foreach($appIds as $appId) {
951
+                $appId = \OC_App::cleanAppId($appId);
952
+                \OC::$server->getAppManager()->disableApp($appId);
953
+            }
954
+            \OC_JSON::success();
955
+            exit();
956
+        }
957
+
958
+        // Always load authentication apps
959
+        OC_App::loadApps(['authentication']);
960
+
961
+        // Load minimum set of apps
962
+        if (!\OCP\Util::needUpgrade()
963
+            && !$systemConfig->getValue('maintenance', false)) {
964
+            // For logged-in users: Load everything
965
+            if(\OC::$server->getUserSession()->isLoggedIn()) {
966
+                OC_App::loadApps();
967
+            } else {
968
+                // For guests: Load only filesystem and logging
969
+                OC_App::loadApps(array('filesystem', 'logging'));
970
+                self::handleLogin($request);
971
+            }
972
+        }
973
+
974
+        if (!self::$CLI) {
975
+            try {
976
+                if (!$systemConfig->getValue('maintenance', false) && !\OCP\Util::needUpgrade()) {
977
+                    OC_App::loadApps(array('filesystem', 'logging'));
978
+                    OC_App::loadApps();
979
+                }
980
+                OC_Util::setupFS();
981
+                OC::$server->getRouter()->match(\OC::$server->getRequest()->getRawPathInfo());
982
+                return;
983
+            } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
984
+                //header('HTTP/1.0 404 Not Found');
985
+            } catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
986
+                OC_Response::setStatus(405);
987
+                return;
988
+            }
989
+        }
990
+
991
+        // Handle WebDAV
992
+        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
993
+            // not allowed any more to prevent people
994
+            // mounting this root directly.
995
+            // Users need to mount remote.php/webdav instead.
996
+            header('HTTP/1.1 405 Method Not Allowed');
997
+            header('Status: 405 Method Not Allowed');
998
+            return;
999
+        }
1000
+
1001
+        // Someone is logged in
1002
+        if (\OC::$server->getUserSession()->isLoggedIn()) {
1003
+            OC_App::loadApps();
1004
+            OC_User::setupBackends();
1005
+            OC_Util::setupFS();
1006
+            // FIXME
1007
+            // Redirect to default application
1008
+            OC_Util::redirectToDefaultPage();
1009
+        } else {
1010
+            // Not handled and not logged in
1011
+            header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
1012
+        }
1013
+    }
1014
+
1015
+    /**
1016
+     * Check login: apache auth, auth token, basic auth
1017
+     *
1018
+     * @param OCP\IRequest $request
1019
+     * @return boolean
1020
+     */
1021
+    static function handleLogin(OCP\IRequest $request) {
1022
+        $userSession = self::$server->getUserSession();
1023
+        if (OC_User::handleApacheAuth()) {
1024
+            return true;
1025
+        }
1026
+        if ($userSession->tryTokenLogin($request)) {
1027
+            return true;
1028
+        }
1029
+        if (isset($_COOKIE['nc_username'])
1030
+            && isset($_COOKIE['nc_token'])
1031
+            && isset($_COOKIE['nc_session_id'])
1032
+            && $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
1033
+            return true;
1034
+        }
1035
+        if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
1036
+            return true;
1037
+        }
1038
+        return false;
1039
+    }
1040
+
1041
+    protected static function handleAuthHeaders() {
1042
+        //copy http auth headers for apache+php-fcgid work around
1043
+        if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
1044
+            $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
1045
+        }
1046
+
1047
+        // Extract PHP_AUTH_USER/PHP_AUTH_PW from other headers if necessary.
1048
+        $vars = array(
1049
+            'HTTP_AUTHORIZATION', // apache+php-cgi work around
1050
+            'REDIRECT_HTTP_AUTHORIZATION', // apache+php-cgi alternative
1051
+        );
1052
+        foreach ($vars as $var) {
1053
+            if (isset($_SERVER[$var]) && preg_match('/Basic\s+(.*)$/i', $_SERVER[$var], $matches)) {
1054
+                list($name, $password) = explode(':', base64_decode($matches[1]), 2);
1055
+                $_SERVER['PHP_AUTH_USER'] = $name;
1056
+                $_SERVER['PHP_AUTH_PW'] = $password;
1057
+                break;
1058
+            }
1059
+        }
1060
+    }
1061 1061
 }
1062 1062
 
1063 1063
 OC::init();
Please login to merge, or discard this patch.