aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/AllConfig.php19
-rw-r--r--lib/private/App/DependencyAnalyzer.php6
-rw-r--r--lib/private/App/InfoParser.php51
-rw-r--r--lib/private/AppFramework/App.php21
-rw-r--r--lib/private/AppFramework/Db/Db.php11
-rw-r--r--lib/private/AppFramework/DependencyInjection/DIContainer.php18
-rw-r--r--lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php23
-rw-r--r--lib/private/AppFramework/OCS/BaseResponse.php3
-rw-r--r--lib/private/AppFramework/Routing/RouteConfig.php16
-rw-r--r--lib/private/AppFramework/Utility/SimpleContainer.php19
-rw-r--r--lib/private/Avatar.php25
-rw-r--r--lib/private/AvatarManager.php29
-rw-r--r--lib/private/Comments/Manager.php85
-rw-r--r--lib/private/Console/Application.php74
-rw-r--r--lib/private/DB/AdapterMySQL.php14
-rw-r--r--lib/private/DB/Connection.php11
-rw-r--r--lib/private/DB/ConnectionFactory.php11
-rw-r--r--lib/private/DB/MDB2SchemaManager.php11
-rw-r--r--lib/private/DB/MDB2SchemaReader.php14
-rw-r--r--lib/private/DB/MDB2SchemaWriter.php6
-rw-r--r--lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php19
-rw-r--r--lib/private/Encryption/DecryptAll.php2
-rw-r--r--lib/private/Encryption/EncryptionWrapper.php2
-rw-r--r--lib/private/Files/AppData/AppData.php131
-rw-r--r--lib/private/Files/AppData/Factory.php50
-rw-r--r--lib/private/Files/Config/CachedMountInfo.php20
-rw-r--r--lib/private/Files/Config/LazyStorageMountInfo.php9
-rw-r--r--lib/private/Files/Config/UserMountCache.php30
-rw-r--r--lib/private/Files/Filesystem.php2
-rw-r--r--lib/private/Files/Node/Folder.php74
-rw-r--r--lib/private/Files/Node/Root.php14
-rw-r--r--lib/private/Files/SimpleFS/SimpleFile.php115
-rw-r--r--lib/private/Files/SimpleFS/SimpleFolder.php87
-rw-r--r--lib/private/Files/Storage/Common.php4
-rw-r--r--lib/private/Files/Storage/Local.php21
-rw-r--r--lib/private/Files/Storage/Wrapper/PermissionsMask.php8
-rw-r--r--lib/private/Files/Storage/Wrapper/Wrapper.php4
-rw-r--r--lib/private/Files/Stream/OC.php154
-rw-r--r--lib/private/Files/Type/Detection.php6
-rw-r--r--lib/private/Files/View.php10
-rw-r--r--lib/private/Installer.php2
-rw-r--r--lib/private/IntegrityCheck/Checker.php2
-rw-r--r--lib/private/L10N/Factory.php30
-rw-r--r--lib/private/LargeFileHelper.php30
-rw-r--r--lib/private/Log.php4
-rw-r--r--lib/private/Log/File.php6
-rw-r--r--lib/private/Notification/Notification.php32
-rw-r--r--lib/private/Preview.php8
-rw-r--r--lib/private/PreviewNotAvailableException.php27
-rw-r--r--lib/private/Repair.php10
-rw-r--r--lib/private/Repair/Collation.php45
-rw-r--r--lib/private/Repair/MoveUpdaterStepFile.php80
-rw-r--r--lib/private/Repair/NC11/MoveAvatarBackgroundJob.php104
-rw-r--r--lib/private/Repair/NC11/MoveAvatars.php64
-rw-r--r--lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php82
-rw-r--r--lib/private/Security/CSRF/CsrfToken.php10
-rw-r--r--lib/private/Security/CSRF/CsrfTokenManager.php13
-rw-r--r--lib/private/Server.php38
-rw-r--r--lib/private/Setup.php6
-rw-r--r--lib/private/Setup/AbstractDatabase.php2
-rw-r--r--lib/private/Setup/MySQL.php5
-rw-r--r--lib/private/Share/Share.php4
-rw-r--r--lib/private/Share20/DefaultShareProvider.php125
-rw-r--r--lib/private/Share20/Manager.php3
-rw-r--r--lib/private/Share20/Share.php2
-rw-r--r--lib/private/Template/JSConfigHelper.php243
-rw-r--r--lib/private/TemplateLayout.php18
-rw-r--r--lib/private/Updater.php123
-rw-r--r--lib/private/Updater/VersionCheck.php3
-rw-r--r--lib/private/User/Database.php9
-rw-r--r--lib/private/User/Session.php5
-rw-r--r--lib/private/User/User.php10
-rw-r--r--lib/private/legacy/app.php130
-rw-r--r--lib/private/legacy/db.php17
-rw-r--r--lib/private/legacy/helper.php42
-rw-r--r--lib/private/legacy/ocs.php2
-rw-r--r--lib/private/legacy/response.php1
-rw-r--r--lib/private/legacy/template.php9
-rw-r--r--lib/private/legacy/util.php52
79 files changed, 1990 insertions, 637 deletions
diff --git a/lib/private/AllConfig.php b/lib/private/AllConfig.php
index 52d77bf3f52..af26d30d8e9 100644
--- a/lib/private/AllConfig.php
+++ b/lib/private/AllConfig.php
@@ -215,6 +215,25 @@ class AllConfig implements \OCP\IConfig {
// TODO - FIXME
$this->fixDIInit();
+ if (isset($this->userCache[$userId][$appName][$key])) {
+ if ($this->userCache[$userId][$appName][$key] === (string)$value) {
+ return;
+ } else if ($preCondition !== null && $this->userCache[$userId][$appName][$key] !== (string)$preCondition) {
+ return;
+ } else {
+ $qb = $this->connection->getQueryBuilder();
+ $qb->update('preferences')
+ ->set('configvalue', $qb->createNamedParameter($value))
+ ->where($qb->expr()->eq('userid', $qb->createNamedParameter($userId)))
+ ->andWhere($qb->expr()->eq('appid', $qb->createNamedParameter($appName)))
+ ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key)));
+ $qb->execute();
+
+ $this->userCache[$userId][$appName][$key] = $value;
+ return;
+ }
+ }
+
$preconditionArray = [];
if (isset($preCondition)) {
$preconditionArray = [
diff --git a/lib/private/App/DependencyAnalyzer.php b/lib/private/App/DependencyAnalyzer.php
index 7adb5d1c574..67268981e99 100644
--- a/lib/private/App/DependencyAnalyzer.php
+++ b/lib/private/App/DependencyAnalyzer.php
@@ -197,6 +197,9 @@ class DependencyAnalyzer {
if (!is_array($commands)) {
$commands = array($commands);
}
+ if (isset($commands['@value'])) {
+ $commands = [$commands];
+ }
$os = $this->platform->getOS();
foreach ($commands as $command) {
if (isset($command['@attributes']['os']) && $command['@attributes']['os'] !== $os) {
@@ -224,6 +227,9 @@ class DependencyAnalyzer {
if (!is_array($libs)) {
$libs = array($libs);
}
+ if (isset($libs['@value'])) {
+ $libs = [$libs];
+ }
foreach ($libs as $lib) {
$libName = $this->getValue($lib);
$libVersion = $this->platform->getLibraryVersion($libName);
diff --git a/lib/private/App/InfoParser.php b/lib/private/App/InfoParser.php
index e975ad6f096..44f495534c9 100644
--- a/lib/private/App/InfoParser.php
+++ b/lib/private/App/InfoParser.php
@@ -1,6 +1,7 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
*
* @author Andreas Fischer <bantu@owncloud.com>
* @author Christoph Wurst <christoph@owncloud.com>
@@ -26,18 +27,17 @@
namespace OC\App;
-use OCP\IURLGenerator;
+use OCP\ICache;
class InfoParser {
-
- /** @var IURLGenerator */
- private $urlGenerator;
+ /** @var \OCP\ICache|null */
+ private $cache;
/**
- * @param IURLGenerator $urlGenerator
+ * @param ICache|null $cache
*/
- public function __construct(IURLGenerator $urlGenerator) {
- $this->urlGenerator = $urlGenerator;
+ public function __construct(ICache $cache = null) {
+ $this->cache = $cache;
}
/**
@@ -49,18 +49,28 @@ class InfoParser {
return null;
}
+ if(!is_null($this->cache)) {
+ $fileCacheKey = $file . filemtime($file);
+ if ($cachedValue = $this->cache->get($fileCacheKey)) {
+ return json_decode($cachedValue, true);
+ }
+ }
+
libxml_use_internal_errors(true);
$loadEntities = libxml_disable_entity_loader(false);
$xml = simplexml_load_file($file);
+
libxml_disable_entity_loader($loadEntities);
- if ($xml == false) {
+ if ($xml === false) {
libxml_clear_errors();
return null;
}
$array = $this->xmlToArray($xml);
+
if (is_null($array)) {
return null;
}
+
if (!array_key_exists('info', $array)) {
$array['info'] = [];
}
@@ -97,18 +107,10 @@ class InfoParser {
if (!array_key_exists('two-factor-providers', $array)) {
$array['two-factor-providers'] = [];
}
-
- if (array_key_exists('documentation', $array) && is_array($array['documentation'])) {
- foreach ($array['documentation'] as $key => $url) {
- // If it is not an absolute URL we assume it is a key
- // i.e. admin-ldap will get converted to go.php?to=admin-ldap
- if (!$this->isHTTPURL($url)) {
- $url = $this->urlGenerator->linkToDocs($url);
- }
-
- $array['documentation'][$key] = $url;
- }
+ if (!array_key_exists('commands', $array)) {
+ $array['commands'] = [];
}
+
if (array_key_exists('types', $array)) {
if (is_array($array['types'])) {
foreach ($array['types'] as $type => $v) {
@@ -139,6 +141,13 @@ class InfoParser {
if (isset($array['background-jobs']['job']) && is_array($array['background-jobs']['job'])) {
$array['background-jobs'] = $array['background-jobs']['job'];
}
+ if (isset($array['commands']['command']) && is_array($array['commands']['command'])) {
+ $array['commands'] = $array['commands']['command'];
+ }
+
+ if(!is_null($this->cache)) {
+ $this->cache->set($fileCacheKey, json_encode($array));
+ }
return $array;
}
@@ -193,8 +202,4 @@ class InfoParser {
return $array;
}
-
- private function isHTTPURL($url) {
- return stripos($url, 'https://') === 0 || stripos($url, 'http://') === 0;
- }
}
diff --git a/lib/private/AppFramework/App.php b/lib/private/AppFramework/App.php
index 427a850f396..e15e4a797ea 100644
--- a/lib/private/AppFramework/App.php
+++ b/lib/private/AppFramework/App.php
@@ -59,24 +59,11 @@ class App {
return $topNamespace . self::$nameSpaceCache[$appId];
}
- // first try to parse the app's appinfo/info.xml <namespace> tag
- $appPath = OC_App::getAppPath($appId);
- if ($appPath !== false) {
- $filePath = "$appPath/appinfo/info.xml";
- if (is_file($filePath)) {
- $loadEntities = libxml_disable_entity_loader(false);
- $xml = @simplexml_load_file($filePath);
- libxml_disable_entity_loader($loadEntities);
- if ($xml) {
- $result = $xml->xpath('/info/namespace');
- if ($result && count($result) > 0) {
- self::$nameSpaceCache[$appId] = trim((string) $result[0]);
- // take first namespace result
- return $topNamespace . self::$nameSpaceCache[$appId];
- }
- }
- }
+ $appInfo = \OC_App::getAppInfo($appId);
+ if (isset($appInfo['namespace'])) {
+ return $topNamespace . trim($appInfo['namespace']);
}
+
// if the tag is not found, fall back to uppercasing the first letter
self::$nameSpaceCache[$appId] = ucfirst($appId);
return $topNamespace . self::$nameSpaceCache[$appId];
diff --git a/lib/private/AppFramework/Db/Db.php b/lib/private/AppFramework/Db/Db.php
index 5fea09747af..450549ffdbb 100644
--- a/lib/private/AppFramework/Db/Db.php
+++ b/lib/private/AppFramework/Db/Db.php
@@ -31,6 +31,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDb;
use OCP\IDBConnection;
use OCP\PreConditionNotMetException;
+use Doctrine\DBAL\Platforms\MySqlPlatform;
/**
* @deprecated use IDBConnection directly, will be removed in ownCloud 10
@@ -300,4 +301,14 @@ class Db implements IDb {
public function escapeLikeParameter($param) {
return $this->connection->escapeLikeParameter($param);
}
+
+ /**
+ * Check whether or not the current database support 4byte wide unicode
+ *
+ * @return bool
+ * @since 9.2.0
+ */
+ public function supports4ByteText() {
+ return $this->connection->supports4ByteText();
+ }
}
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index 20351d1321c..8fe9b4dca03 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -46,7 +46,8 @@ use OC\AppFramework\Utility\SimpleContainer;
use OC\Core\Middleware\TwoFactorMiddleware;
use OCP\AppFramework\IApi;
use OCP\AppFramework\IAppContainer;
-
+use OCP\Files\IAppData;
+use OCP\Files\Mount\IMountManager;
class DIContainer extends SimpleContainer implements IAppContainer {
@@ -160,10 +161,18 @@ class DIContainer extends SimpleContainer implements IAppContainer {
return $this->getServer()->getRootFolder();
});
+ $this->registerService('OCP\\Files\\Folder', function() {
+ return $this->getServer()->getUserFolder();
+ });
+
$this->registerService('OCP\\Http\\Client\\IClientService', function($c) {
return $this->getServer()->getHTTPClientService();
});
+ $this->registerService(IAppData::class, function (SimpleContainer $c) {
+ return $this->getServer()->getAppDataDir($c->query('AppName'));
+ });
+
$this->registerService('OCP\\IGroupManager', function($c) {
return $this->getServer()->getGroupManager();
});
@@ -304,6 +313,9 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$this->registerService('OCP\\AppFramework\\IAppContainer', function ($c) {
return $c;
});
+ $this->registerService(IMountManager::class, function () {
+ return $this->getServer()->getMountManager();
+ });
// commonly used attributes
$this->registerService('UserId', function ($c) {
@@ -367,7 +379,9 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$c['AppName'],
$app->isLoggedIn(),
$app->isAdminUser(),
- $app->getServer()->getContentSecurityPolicyManager()
+ $app->getServer()->getContentSecurityPolicyManager(),
+ $app->getServer()->getCsrfTokenManager(),
+ $app->getServer()->getContentSecurityPolicyNonceManager()
);
});
diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
index 3bfef2df025..183e55740ea 100644
--- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
@@ -36,7 +36,10 @@ use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException;
use OC\AppFramework\Middleware\Security\Exceptions\StrictCookieMissingException;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OC\Security\CSP\ContentSecurityPolicyManager;
+use OC\Security\CSP\ContentSecurityPolicyNonceManager;
+use OC\Security\CSRF\CsrfTokenManager;
use OCP\AppFramework\Http\ContentSecurityPolicy;
+use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Middleware;
@@ -76,6 +79,10 @@ class SecurityMiddleware extends Middleware {
private $isAdminUser;
/** @var ContentSecurityPolicyManager */
private $contentSecurityPolicyManager;
+ /** @var CsrfTokenManager */
+ private $csrfTokenManager;
+ /** @var ContentSecurityPolicyNonceManager */
+ private $cspNonceManager;
/**
* @param IRequest $request
@@ -87,6 +94,8 @@ class SecurityMiddleware extends Middleware {
* @param bool $isLoggedIn
* @param bool $isAdminUser
* @param ContentSecurityPolicyManager $contentSecurityPolicyManager
+ * @param CSRFTokenManager $csrfTokenManager
+ * @param ContentSecurityPolicyNonceManager $cspNonceManager
*/
public function __construct(IRequest $request,
ControllerMethodReflector $reflector,
@@ -96,7 +105,9 @@ class SecurityMiddleware extends Middleware {
$appName,
$isLoggedIn,
$isAdminUser,
- ContentSecurityPolicyManager $contentSecurityPolicyManager) {
+ ContentSecurityPolicyManager $contentSecurityPolicyManager,
+ CsrfTokenManager $csrfTokenManager,
+ ContentSecurityPolicyNonceManager $cspNonceManager) {
$this->navigationManager = $navigationManager;
$this->request = $request;
$this->reflector = $reflector;
@@ -106,6 +117,8 @@ class SecurityMiddleware extends Middleware {
$this->isLoggedIn = $isLoggedIn;
$this->isAdminUser = $isAdminUser;
$this->contentSecurityPolicyManager = $contentSecurityPolicyManager;
+ $this->csrfTokenManager = $csrfTokenManager;
+ $this->cspNonceManager = $cspNonceManager;
}
@@ -182,9 +195,17 @@ class SecurityMiddleware extends Middleware {
public function afterController($controller, $methodName, Response $response) {
$policy = !is_null($response->getContentSecurityPolicy()) ? $response->getContentSecurityPolicy() : new ContentSecurityPolicy();
+ if (get_class($policy) === EmptyContentSecurityPolicy::class) {
+ return $response;
+ }
+
$defaultPolicy = $this->contentSecurityPolicyManager->getDefaultPolicy();
$defaultPolicy = $this->contentSecurityPolicyManager->mergePolicies($defaultPolicy, $policy);
+ if($this->cspNonceManager->browserSupportsCspV3()) {
+ $defaultPolicy->useJsNonce($this->csrfTokenManager->getToken()->getEncryptedValue());
+ }
+
$response->setContentSecurityPolicy($defaultPolicy);
return $response;
diff --git a/lib/private/AppFramework/OCS/BaseResponse.php b/lib/private/AppFramework/OCS/BaseResponse.php
index fa22498ac0f..59b8660a382 100644
--- a/lib/private/AppFramework/OCS/BaseResponse.php
+++ b/lib/private/AppFramework/OCS/BaseResponse.php
@@ -23,6 +23,7 @@
namespace OC\AppFramework\OCS;
use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
use OCP\AppFramework\Http\Response;
abstract class BaseResponse extends Response {
@@ -67,7 +68,7 @@ abstract class BaseResponse extends Response {
$this->setETag($dataResponse->getETag());
$this->setLastModified($dataResponse->getLastModified());
$this->setCookies($dataResponse->getCookies());
- $this->setContentSecurityPolicy($dataResponse->getContentSecurityPolicy());
+ $this->setContentSecurityPolicy(new EmptyContentSecurityPolicy());
if ($format === 'json') {
$this->addHeader(
diff --git a/lib/private/AppFramework/Routing/RouteConfig.php b/lib/private/AppFramework/Routing/RouteConfig.php
index e94f2e50c1d..70208725f46 100644
--- a/lib/private/AppFramework/Routing/RouteConfig.php
+++ b/lib/private/AppFramework/Routing/RouteConfig.php
@@ -36,14 +36,25 @@ use OCP\Route\IRouter;
* @package OC\AppFramework\routing
*/
class RouteConfig {
+ /** @var DIContainer */
private $container;
+
+ /** @var IRouter */
private $router;
+
+ /** @var array */
private $routes;
+
+ /** @var string */
private $appName;
+ /** @var string[] */
+ private $controllerNameCache = [];
+
/**
* @param \OC\AppFramework\DependencyInjection\DIContainer $container
* @param \OCP\Route\IRouter $router
+ * @param array $routes
* @internal param $appName
*/
public function __construct(DIContainer $container, IRouter $router, $routes) {
@@ -234,7 +245,10 @@ class RouteConfig {
*/
private function buildControllerName($controller)
{
- return $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller';
+ if (!isset($this->controllerNameCache[$controller])) {
+ $this->controllerNameCache[$controller] = $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller';
+ }
+ return $this->controllerNameCache[$controller];
}
/**
diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php
index 5f637518f4d..889f17cbc6a 100644
--- a/lib/private/AppFramework/Utility/SimpleContainer.php
+++ b/lib/private/AppFramework/Utility/SimpleContainer.php
@@ -62,7 +62,19 @@ class SimpleContainer extends Container implements IContainer {
$resolveName = $parameterClass->name;
}
- $parameters[] = $this->query($resolveName);
+ try {
+ $parameters[] = $this->query($resolveName);
+ } catch (\Exception $e) {
+ // Service not found, use the default value when available
+ if ($parameter->isDefaultValueAvailable()) {
+ $parameters[] = $parameter->getDefaultValue();
+ } else if ($parameterClass !== null) {
+ $resolveName = $parameter->getName();
+ $parameters[] = $this->query($resolveName);
+ } else {
+ throw $e;
+ }
+ }
}
return $class->newInstanceArgs($parameters);
}
@@ -157,7 +169,10 @@ class SimpleContainer extends Container implements IContainer {
* @return string
*/
protected function sanitizeName($name) {
- return ltrim($name, '\\');
+ if (isset($name[0]) && $name[0] === '\\') {
+ return ltrim($name, '\\');
+ }
+ return $name;
}
}
diff --git a/lib/private/Avatar.php b/lib/private/Avatar.php
index 9e8bd0136c2..fc1909c3bda 100644
--- a/lib/private/Avatar.php
+++ b/lib/private/Avatar.php
@@ -29,10 +29,10 @@
namespace OC;
use OC\User\User;
-use OCP\Files\Folder;
-use OCP\Files\File;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IAvatar;
use OCP\IConfig;
use OCP\IImage;
@@ -45,7 +45,7 @@ use OCP\ILogger;
*/
class Avatar implements IAvatar {
- /** @var Folder */
+ /** @var ISimpleFolder */
private $folder;
/** @var IL10N */
private $l;
@@ -59,13 +59,13 @@ class Avatar implements IAvatar {
/**
* constructor
*
- * @param Folder $folder The folder where the avatars are
+ * @param ISimpleFolder $folder The folder where the avatars are
* @param IL10N $l
* @param User $user
* @param ILogger $logger
* @param IConfig $config
*/
- public function __construct(Folder $folder,
+ public function __construct(ISimpleFolder $folder,
IL10N $l,
$user,
ILogger $logger,
@@ -98,7 +98,8 @@ class Avatar implements IAvatar {
* @return bool
*/
public function exists() {
- return $this->folder->nodeExists('avatar.jpg') || $this->folder->nodeExists('avatar.png');
+
+ return $this->folder->fileExists('avatar.jpg') || $this->folder->fileExists('avatar.png');
}
/**
@@ -130,7 +131,7 @@ class Avatar implements IAvatar {
}
if (!($img->height() === $img->width())) {
- throw new NotSquareException();
+ throw new NotSquareException($this->l->t("Avatar image is not square"));
}
$this->remove();
@@ -170,15 +171,15 @@ class Avatar implements IAvatar {
}
try {
- $file = $this->folder->get($path);
+ $file = $this->folder->getFile($path);
} catch (NotFoundException $e) {
if ($size <= 0) {
throw new NotFoundException;
}
$avatar = new OC_Image();
- /** @var File $file */
- $file = $this->folder->get('avatar.' . $ext);
+ /** @var ISimpleFile $file */
+ $file = $this->folder->getFile('avatar.' . $ext);
$avatar->loadFromData($file->getContent());
if ($size !== -1) {
$avatar->resize($size);
@@ -201,9 +202,9 @@ class Avatar implements IAvatar {
* @throws NotFoundException
*/
private function getExtension() {
- if ($this->folder->nodeExists('avatar.jpg')) {
+ if ($this->folder->fileExists('avatar.jpg')) {
return 'jpg';
- } elseif ($this->folder->nodeExists('avatar.png')) {
+ } elseif ($this->folder->fileExists('avatar.png')) {
return 'png';
}
throw new NotFoundException;
diff --git a/lib/private/AvatarManager.php b/lib/private/AvatarManager.php
index 0eabc3a1754..b8c6c2a1eb6 100644
--- a/lib/private/AvatarManager.php
+++ b/lib/private/AvatarManager.php
@@ -27,13 +27,12 @@
namespace OC;
-use OCP\Files\Folder;
+use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\IAvatarManager;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUserManager;
-use OCP\Files\IRootFolder;
use OCP\IL10N;
/**
@@ -44,8 +43,8 @@ class AvatarManager implements IAvatarManager {
/** @var IUserManager */
private $userManager;
- /** @var IRootFolder */
- private $rootFolder;
+ /** @var IAppData */
+ private $appData;
/** @var IL10N */
private $l;
@@ -60,19 +59,19 @@ class AvatarManager implements IAvatarManager {
* AvatarManager constructor.
*
* @param IUserManager $userManager
- * @param IRootFolder $rootFolder
+ * @param IAppData $appData
* @param IL10N $l
* @param ILogger $logger
* @param IConfig $config
*/
public function __construct(
IUserManager $userManager,
- IRootFolder $rootFolder,
+ IAppData $appData,
IL10N $l,
ILogger $logger,
IConfig $config) {
$this->userManager = $userManager;
- $this->rootFolder = $rootFolder;
+ $this->appData = $appData;
$this->l = $l;
$this->logger = $logger;
$this->config = $config;
@@ -92,14 +91,14 @@ class AvatarManager implements IAvatarManager {
throw new \Exception('user does not exist');
}
- /*
- * Fix for #22119
- * Basically we do not want to copy the skeleton folder
- */
- \OC\Files\Filesystem::initMountPoints($userId);
- $dir = '/' . $userId;
- /** @var Folder $folder */
- $folder = $this->rootFolder->get($dir);
+ // sanitize userID - fixes casing issue (needed for the filesystem stuff that is done below)
+ $userId = $user->getUID();
+
+ try {
+ $folder = $this->appData->getFolder($userId);
+ } catch (NotFoundException $e) {
+ $folder = $this->appData->newFolder($userId);
+ }
return new Avatar($folder, $this->l, $user, $this->logger, $this->config);
}
diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php
index 59678775d88..b3ecab731e1 100644
--- a/lib/private/Comments/Manager.php
+++ b/lib/private/Comments/Manager.php
@@ -26,6 +26,7 @@ namespace OC\Comments;
use Doctrine\DBAL\Exception\DriverException;
use OCP\Comments\CommentsEvent;
use OCP\Comments\IComment;
+use OCP\Comments\ICommentsEventHandler;
use OCP\Comments\ICommentsManager;
use OCP\Comments\NotFoundException;
use OCP\DB\QueryBuilder\IQueryBuilder;
@@ -33,7 +34,6 @@ use OCP\IDBConnection;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUser;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class Manager implements ICommentsManager {
@@ -46,30 +46,30 @@ class Manager implements ICommentsManager {
/** @var IConfig */
protected $config;
- /** @var EventDispatcherInterface */
- protected $dispatcher;
-
/** @var IComment[] */
protected $commentsCache = [];
+ /** @var \Closure[] */
+ protected $eventHandlerClosures = [];
+
+ /** @var ICommentsEventHandler[] */
+ protected $eventHandlers = [];
+
/**
* Manager constructor.
*
* @param IDBConnection $dbConn
* @param ILogger $logger
* @param IConfig $config
- * @param EventDispatcherInterface $dispatcher
*/
public function __construct(
IDBConnection $dbConn,
ILogger $logger,
- IConfig $config,
- EventDispatcherInterface $dispatcher
+ IConfig $config
) {
$this->dbConn = $dbConn;
$this->logger = $logger;
$this->config = $config;
- $this->dispatcher = $dispatcher;
}
/**
@@ -455,10 +455,7 @@ class Manager implements ICommentsManager {
}
if ($affectedRows > 0 && $comment instanceof IComment) {
- $this->dispatcher->dispatch(CommentsEvent::EVENT_DELETE, new CommentsEvent(
- CommentsEvent::EVENT_DELETE,
- $comment
- ));
+ $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment);
}
return ($affectedRows > 0);
@@ -525,13 +522,9 @@ class Manager implements ICommentsManager {
if ($affectedRows > 0) {
$comment->setId(strval($qb->getLastInsertId()));
+ $this->sendEvent(CommentsEvent::EVENT_ADD, $comment);
}
- $this->dispatcher->dispatch(CommentsEvent::EVENT_ADD, new CommentsEvent(
- CommentsEvent::EVENT_ADD,
- $comment
- ));
-
return $affectedRows > 0;
}
@@ -543,6 +536,12 @@ class Manager implements ICommentsManager {
* @throws NotFoundException
*/
protected function update(IComment $comment) {
+ // for properly working preUpdate Events we need the old comments as is
+ // in the DB and overcome caching. Also avoid that outdated information stays.
+ $this->uncache($comment->getId());
+ $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId()));
+ $this->uncache($comment->getId());
+
$qb = $this->dbConn->getQueryBuilder();
$affectedRows = $qb
->update('comments')
@@ -565,10 +564,7 @@ class Manager implements ICommentsManager {
throw new NotFoundException('Comment to update does ceased to exist');
}
- $this->dispatcher->dispatch(CommentsEvent::EVENT_UPDATE, new CommentsEvent(
- CommentsEvent::EVENT_UPDATE,
- $comment
- ));
+ $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment);
return $affectedRows > 0;
}
@@ -751,4 +747,51 @@ class Manager implements ICommentsManager {
}
return ($affectedRows > 0);
}
+
+ /**
+ * registers an Entity to the manager, so event notifications can be send
+ * to consumers of the comments infrastructure
+ *
+ * @param \Closure $closure
+ */
+ public function registerEventHandler(\Closure $closure) {
+ $this->eventHandlerClosures[] = $closure;
+ $this->eventHandlers = [];
+ }
+
+ /**
+ * returns valid, registered entities
+ *
+ * @return \OCP\Comments\ICommentsEventHandler[]
+ */
+ private function getEventHandlers() {
+ if(!empty($this->eventHandlers)) {
+ return $this->eventHandlers;
+ }
+
+ $this->eventHandlers = [];
+ foreach ($this->eventHandlerClosures as $name => $closure) {
+ $entity = $closure();
+ if (!($entity instanceof ICommentsEventHandler)) {
+ throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface');
+ }
+ $this->eventHandlers[$name] = $entity;
+ }
+
+ return $this->eventHandlers;
+ }
+
+ /**
+ * sends notifications to the registered entities
+ *
+ * @param $eventType
+ * @param IComment $comment
+ */
+ private function sendEvent($eventType, IComment $comment) {
+ $entities = $this->getEventHandlers();
+ $event = new CommentsEvent($eventType, $comment);
+ foreach ($entities as $entity) {
+ $entity->handle($event);
+ }
+ }
}
diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php
index cad16a070c8..cd76b43f095 100644
--- a/lib/private/Console/Application.php
+++ b/lib/private/Console/Application.php
@@ -26,13 +26,13 @@
*/
namespace OC\Console;
+use OC\NeedsUpdateException;
use OC_App;
+use OCP\AppFramework\QueryException;
use OCP\Console\ConsoleEvent;
-use OCP\Defaults;
use OCP\IConfig;
use OCP\IRequest;
use Symfony\Component\Console\Application as SymfonyApplication;
-use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -85,31 +85,45 @@ class Application {
if ($input->getOption('no-warnings')) {
$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
}
- require_once __DIR__ . '/../../../core/register_command.php';
- if ($this->config->getSystemValue('installed', false)) {
- if (\OCP\Util::needUpgrade()) {
- $output->writeln("Nextcloud or one of the apps require upgrade - only a limited number of commands are available");
- $output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
- } elseif ($this->config->getSystemValue('maintenance', false)) {
- $output->writeln("Nextcloud is in maintenance mode - no app have been loaded");
- } else {
- OC_App::loadApps();
- foreach (\OC::$server->getAppManager()->getInstalledApps() as $app) {
- $appPath = \OC_App::getAppPath($app);
- if($appPath === false) {
- continue;
+ try {
+ require_once __DIR__ . '/../../../core/register_command.php';
+ if ($this->config->getSystemValue('installed', false)) {
+ if (\OCP\Util::needUpgrade()) {
+ throw new NeedsUpdateException();
+ } elseif ($this->config->getSystemValue('maintenance', false)) {
+ if ($input->getArgument('command') !== '_completion') {
+ $output->writeln("Nextcloud is in maintenance mode - no apps have been loaded");
}
- \OC_App::registerAutoloading($app, $appPath);
- $file = $appPath . '/appinfo/register_command.php';
- if (file_exists($file)) {
- require $file;
+ } else {
+ OC_App::loadApps();
+ foreach (\OC::$server->getAppManager()->getInstalledApps() as $app) {
+ $appPath = \OC_App::getAppPath($app);
+ if ($appPath === false) {
+ continue;
+ }
+ // load commands using info.xml
+ $info = \OC_App::getAppInfo($app);
+ if (isset($info['commands'])) {
+ $this->loadCommandsFromInfoXml($info['commands']);
+ }
+ // load from register_command.php
+ \OC_App::registerAutoloading($app, $appPath);
+ $file = $appPath . '/appinfo/register_command.php';
+ if (file_exists($file)) {
+ require $file;
+ }
}
}
+ } else if ($input->getArgument('command') !== '_completion') {
+ $output->writeln("Nextcloud is not installed - only a limited number of commands are available");
+ }
+ } catch(NeedsUpdateException $e) {
+ if ($input->getArgument('command') !== '_completion') {
+ $output->writeln("Nextcloud or one of the apps require upgrade - only a limited number of commands are available");
+ $output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
}
- } else {
- $output->writeln("Nextcloud is not installed - only a limited number of commands are available");
}
- $input = new ArgvInput();
+
if ($input->getFirstArgument() !== 'check') {
$errors = \OC_Util::checkServer(\OC::$server->getConfig());
if (!empty($errors)) {
@@ -145,4 +159,20 @@ class Application {
));
return $this->application->run($input, $output);
}
+
+ private function loadCommandsFromInfoXml($commands) {
+ foreach ($commands as $command) {
+ try {
+ $c = \OC::$server->query($command);
+ } catch (QueryException $e) {
+ if (class_exists($command)) {
+ $c = new $command();
+ } else {
+ throw new \Exception("Console command '$command' is unknown and could not be loaded");
+ }
+ }
+
+ $this->application->add($c);
+ }
+ }
}
diff --git a/lib/private/DB/AdapterMySQL.php b/lib/private/DB/AdapterMySQL.php
index 3e2fceda8db..aa784bb83dc 100644
--- a/lib/private/DB/AdapterMySQL.php
+++ b/lib/private/DB/AdapterMySQL.php
@@ -27,6 +27,9 @@ namespace OC\DB;
class AdapterMySQL extends Adapter {
+ /** @var string */
+ protected $charset;
+
/**
* @param string $tableName
*/
@@ -39,7 +42,16 @@ class AdapterMySQL extends Adapter {
}
public function fixupStatement($statement) {
- $statement = str_replace(' ILIKE ', ' COLLATE utf8_general_ci LIKE ', $statement);
+ $statement = str_replace(' ILIKE ', ' COLLATE ' . $this->getCharset() . '_general_ci LIKE ', $statement);
return $statement;
}
+
+ protected function getCharset() {
+ if (!$this->charset) {
+ $params = $this->conn->getParams();
+ $this->charset = isset($params['charset']) ? $params['charset'] : 'utf8';
+ }
+
+ return $this->charset;
+ }
}
diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php
index 4fa25aae08d..dfe2e86b617 100644
--- a/lib/private/DB/Connection.php
+++ b/lib/private/DB/Connection.php
@@ -33,6 +33,7 @@ use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\Common\EventManager;
+use Doctrine\DBAL\Platforms\MySqlPlatform;
use OC\DB\QueryBuilder\QueryBuilder;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
@@ -402,4 +403,14 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
public function escapeLikeParameter($param) {
return addcslashes($param, '\\_%');
}
+
+ /**
+ * Check whether or not the current database support 4byte wide unicode
+ *
+ * @return bool
+ * @since 9.2.0
+ */
+ public function supports4ByteText() {
+ return ! ($this->getDatabasePlatform() instanceof MySqlPlatform && $this->getParams()['charset'] !== 'utf8mb4');
+ }
}
diff --git a/lib/private/DB/ConnectionFactory.php b/lib/private/DB/ConnectionFactory.php
index b2c356edef7..adb180da0c0 100644
--- a/lib/private/DB/ConnectionFactory.php
+++ b/lib/private/DB/ConnectionFactory.php
@@ -28,6 +28,7 @@ namespace OC\DB;
use Doctrine\DBAL\Event\Listeners\OracleSessionInit;
use Doctrine\DBAL\Event\Listeners\SQLSessionInit;
use Doctrine\DBAL\Event\Listeners\MysqlSessionInit;
+use OCP\IConfig;
/**
* Takes care of creating and configuring Doctrine connections.
@@ -64,6 +65,12 @@ class ConnectionFactory {
),
);
+ public function __construct(IConfig $config) {
+ if($config->getSystemValue('mysql.utf8mb4', false)) {
+ $this->defaultConnectionParams['mysql']['charset'] = 'utf8mb4';
+ }
+ }
+
/**
* @brief Get default connection parameters for a given DBMS.
* @param string $type DBMS type
@@ -99,7 +106,9 @@ class ConnectionFactory {
case 'mysql':
// Send "SET NAMES utf8". Only required on PHP 5.3 below 5.3.6.
// See http://stackoverflow.com/questions/4361459/php-pdo-charset-set-names#4361485
- $eventManager->addEventSubscriber(new MysqlSessionInit);
+ $eventManager->addEventSubscriber(new MysqlSessionInit(
+ $this->defaultConnectionParams['mysql']['charset']
+ ));
$eventManager->addEventSubscriber(
new SQLSessionInit("SET SESSION AUTOCOMMIT=1"));
break;
diff --git a/lib/private/DB/MDB2SchemaManager.php b/lib/private/DB/MDB2SchemaManager.php
index 494c8fd53f1..f209991eb84 100644
--- a/lib/private/DB/MDB2SchemaManager.php
+++ b/lib/private/DB/MDB2SchemaManager.php
@@ -122,17 +122,6 @@ class MDB2SchemaManager {
}
/**
- * update the database scheme
- * @param string $file file to read structure from
- * @return boolean
- */
- public function simulateUpdateDbFromStructure($file) {
- $toSchema = $this->readSchemaFromFile($file);
- $this->getMigrator()->checkMigrate($toSchema);
- return true;
- }
-
- /**
* @param \Doctrine\DBAL\Schema\Schema $schema
* @return string
*/
diff --git a/lib/private/DB/MDB2SchemaReader.php b/lib/private/DB/MDB2SchemaReader.php
index 3f183c9723a..c198bb31e00 100644
--- a/lib/private/DB/MDB2SchemaReader.php
+++ b/lib/private/DB/MDB2SchemaReader.php
@@ -33,6 +33,7 @@ namespace OC\DB;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\SchemaConfig;
+use Doctrine\DBAL\Platforms\MySqlPlatform;
use OCP\IConfig;
class MDB2SchemaReader {
@@ -54,12 +55,16 @@ class MDB2SchemaReader {
/** @var \Doctrine\DBAL\Schema\SchemaConfig $schemaConfig */
protected $schemaConfig;
+ /** @var IConfig */
+ protected $config;
+
/**
* @param \OCP\IConfig $config
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
*/
public function __construct(IConfig $config, AbstractPlatform $platform) {
$this->platform = $platform;
+ $this->config = $config;
$this->DBNAME = $config->getSystemValue('dbname', 'owncloud');
$this->DBTABLEPREFIX = $config->getSystemValue('dbtableprefix', 'oc_');
@@ -118,8 +123,15 @@ class MDB2SchemaReader {
$name = str_replace('*dbprefix*', $this->DBTABLEPREFIX, $name);
$name = $this->platform->quoteIdentifier($name);
$table = $schema->createTable($name);
- $table->addOption('collate', 'utf8_bin');
$table->setSchemaConfig($this->schemaConfig);
+
+ if($this->platform instanceof MySqlPlatform && $this->config->getSystemValue('mysql.utf8mb4', false)) {
+ $table->addOption('charset', 'utf8mb4');
+ $table->addOption('collate', 'utf8mb4_bin');
+ $table->addOption('row_format', 'compressed');
+ } else {
+ $table->addOption('collate', 'utf8_bin');
+ }
break;
case 'create':
case 'overwrite':
diff --git a/lib/private/DB/MDB2SchemaWriter.php b/lib/private/DB/MDB2SchemaWriter.php
index 26e32b036fe..7664b4359ab 100644
--- a/lib/private/DB/MDB2SchemaWriter.php
+++ b/lib/private/DB/MDB2SchemaWriter.php
@@ -43,7 +43,11 @@ class MDB2SchemaWriter {
$xml->addChild('name', $config->getSystemValue('dbname', 'owncloud'));
$xml->addChild('create', 'true');
$xml->addChild('overwrite', 'false');
- $xml->addChild('charset', 'utf8');
+ if($config->getSystemValue('dbtype', 'sqlite') === 'mysql' && $config->getSystemValue('mysql.utf8mb4', false)) {
+ $xml->addChild('charset', 'utf8mb4');
+ } else {
+ $xml->addChild('charset', 'utf8');
+ }
// FIX ME: bloody work around
if ($config->getSystemValue('dbtype', 'sqlite') === 'oci') {
diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php
index 66d8851632f..17f7fd5aa47 100644
--- a/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php
+++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php
@@ -24,18 +24,31 @@
namespace OC\DB\QueryBuilder\ExpressionBuilder;
-use OC\DB\QueryBuilder\QueryFunction;
-use OCP\DB\QueryBuilder\IQueryBuilder;
+use OC\DB\Connection;
+use OCP\IDBConnection;
class MySqlExpressionBuilder extends ExpressionBuilder {
+ /** @var string */
+ protected $charset;
+
+ /**
+ * @param \OCP\IDBConnection|Connection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ parent::__construct($connection);
+
+ $params = $connection->getParams();
+ $this->charset = isset($params['charset']) ? $params['charset'] : 'utf8';
+ }
+
/**
* @inheritdoc
*/
public function iLike($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
- return $this->expressionBuilder->comparison($x, ' COLLATE utf8_general_ci LIKE', $y);
+ return $this->expressionBuilder->comparison($x, ' COLLATE ' . $this->charset . '_general_ci LIKE', $y);
}
}
diff --git a/lib/private/Encryption/DecryptAll.php b/lib/private/Encryption/DecryptAll.php
index b84395b9e17..caf4237ab9c 100644
--- a/lib/private/Encryption/DecryptAll.php
+++ b/lib/private/Encryption/DecryptAll.php
@@ -211,7 +211,7 @@ class DecryptAll {
$content = $this->rootView->getDirectoryContent($root);
foreach ($content as $file) {
// only decrypt files owned by the user
- if($file->getStorage()->instanceOfStorage('OC\Files\Storage\Shared')) {
+ if($file->getStorage()->instanceOfStorage('OCA\Files_Sharing\SharedStorage')) {
continue;
}
$path = $root . '/' . $file['name'];
diff --git a/lib/private/Encryption/EncryptionWrapper.php b/lib/private/Encryption/EncryptionWrapper.php
index 233390f8739..573fe0159ea 100644
--- a/lib/private/Encryption/EncryptionWrapper.php
+++ b/lib/private/Encryption/EncryptionWrapper.php
@@ -81,7 +81,7 @@ class EncryptionWrapper {
'mount' => $mount
];
- if (!$storage->instanceOfStorage('OC\Files\Storage\Shared')
+ if (!$storage->instanceOfStorage('OCA\Files_Sharing\SharedStorage')
&& !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')
&& !$storage->instanceOfStorage('OC\Files\Storage\OwnCloud')) {
diff --git a/lib/private/Files/AppData/AppData.php b/lib/private/Files/AppData/AppData.php
new file mode 100644
index 00000000000..270e834b8e5
--- /dev/null
+++ b/lib/private/Files/AppData/AppData.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Files\AppData;
+
+use OC\Files\SimpleFS\SimpleFolder;
+use OCP\Files\IAppData;
+use OCP\Files\IRootFolder;
+use OCP\Files\Folder;
+use OC\SystemConfig;
+use OCP\Files\Node;
+use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
+
+class AppData implements IAppData {
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ /** @var SystemConfig */
+ private $config;
+
+ /** @var string */
+ private $appId;
+
+ /** @var Folder */
+ private $folder;
+
+ /**
+ * AppData constructor.
+ *
+ * @param IRootFolder $rootFolder
+ * @param SystemConfig $systemConfig
+ * @param string $appId
+ */
+ public function __construct(IRootFolder $rootFolder,
+ SystemConfig $systemConfig,
+ $appId) {
+
+ $this->rootFolder = $rootFolder;
+ $this->config = $systemConfig;
+ $this->appId = $appId;
+ }
+
+ /**
+ * @return Folder
+ * @throws \RuntimeException
+ */
+ private function getAppDataFolder() {
+ if ($this->folder === null) {
+ $instanceId = $this->config->getValue('instanceid', null);
+ if ($instanceId === null) {
+ throw new \RuntimeException('no instance id!');
+ }
+
+ $name = 'appdata_' . $instanceId;
+
+ try {
+ $appDataFolder = $this->rootFolder->get($name);
+ } catch (NotFoundException $e) {
+ try {
+ $appDataFolder = $this->rootFolder->newFolder($name);
+ } catch (NotPermittedException $e) {
+ throw new \RuntimeException('Could not get appdata folder');
+ }
+ }
+
+ try {
+ $appDataFolder = $appDataFolder->get($this->appId);
+ } catch (NotFoundException $e) {
+ try {
+ $appDataFolder = $appDataFolder->newFolder($this->appId);
+ } catch (NotPermittedException $e) {
+ throw new \RuntimeException('Could not get appdata folder for ' . $this->appId);
+ }
+ }
+
+ $this->folder = $appDataFolder;
+ }
+
+ return $this->folder;
+ }
+
+ public function getFolder($name) {
+ $node = $this->getAppDataFolder()->get($name);
+
+ /** @var Folder $node */
+ return new SimpleFolder($node);
+ }
+
+ public function newFolder($name) {
+ $folder = $this->getAppDataFolder()->newFolder($name);
+
+ return new SimpleFolder($folder);
+ }
+
+ public function getDirectoryListing() {
+ $listing = $this->getAppDataFolder()->getDirectoryListing();
+
+ $fileListing = array_map(function(Node $folder) {
+ if ($folder instanceof Folder) {
+ return new SimpleFolder($folder);
+ }
+ return null;
+ }, $listing);
+
+ $fileListing = array_filter($fileListing);
+
+ return array_values($fileListing);
+ }
+}
diff --git a/lib/private/Files/AppData/Factory.php b/lib/private/Files/AppData/Factory.php
new file mode 100644
index 00000000000..85c75733796
--- /dev/null
+++ b/lib/private/Files/AppData/Factory.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Files\AppData;
+
+use OC\SystemConfig;
+use OCP\Files\IRootFolder;
+
+class Factory {
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ /** @var SystemConfig */
+ private $config;
+
+ public function __construct(IRootFolder $rootFolder,
+ SystemConfig $systemConfig) {
+
+ $this->rootFolder = $rootFolder;
+ $this->config = $systemConfig;
+ }
+
+ /**
+ * @param string $appId
+ * @return AppData
+ */
+ public function get($appId) {
+ return new AppData($this->rootFolder, $this->config, $appId);
+ }
+}
diff --git a/lib/private/Files/Config/CachedMountInfo.php b/lib/private/Files/Config/CachedMountInfo.php
index f68949f8d55..c4132a34431 100644
--- a/lib/private/Files/Config/CachedMountInfo.php
+++ b/lib/private/Files/Config/CachedMountInfo.php
@@ -54,6 +54,11 @@ class CachedMountInfo implements ICachedMountInfo {
protected $mountId;
/**
+ * @var string
+ */
+ protected $rootInternalPath;
+
+ /**
* CachedMountInfo constructor.
*
* @param IUser $user
@@ -61,13 +66,15 @@ class CachedMountInfo implements ICachedMountInfo {
* @param int $rootId
* @param string $mountPoint
* @param int|null $mountId
+ * @param string $rootInternalPath
*/
- public function __construct(IUser $user, $storageId, $rootId, $mountPoint, $mountId = null) {
+ public function __construct(IUser $user, $storageId, $rootId, $mountPoint, $mountId = null, $rootInternalPath = '') {
$this->user = $user;
$this->storageId = $storageId;
$this->rootId = $rootId;
$this->mountPoint = $mountPoint;
$this->mountId = $mountId;
+ $this->rootInternalPath = $rootInternalPath;
}
/**
@@ -98,7 +105,7 @@ class CachedMountInfo implements ICachedMountInfo {
// TODO injection etc
Filesystem::initMountPoints($this->getUser()->getUID());
$userNode = \OC::$server->getUserFolder($this->getUser()->getUID());
- $nodes = $userNode->getById($this->getRootId());
+ $nodes = $userNode->getParent()->getById($this->getRootId());
if (count($nodes) > 0) {
return $nodes[0];
} else {
@@ -122,4 +129,13 @@ class CachedMountInfo implements ICachedMountInfo {
public function getMountId() {
return $this->mountId;
}
+
+ /**
+ * Get the internal path (within the storage) of the root of the mount
+ *
+ * @return string
+ */
+ public function getRootInternalPath() {
+ return $this->rootInternalPath;
+ }
}
diff --git a/lib/private/Files/Config/LazyStorageMountInfo.php b/lib/private/Files/Config/LazyStorageMountInfo.php
index 4df813d57d0..40d463c5103 100644
--- a/lib/private/Files/Config/LazyStorageMountInfo.php
+++ b/lib/private/Files/Config/LazyStorageMountInfo.php
@@ -76,4 +76,13 @@ class LazyStorageMountInfo extends CachedMountInfo {
public function getMountId() {
return $this->mount->getMountId();
}
+
+ /**
+ * Get the internal path (within the storage) of the root of the mount
+ *
+ * @return string
+ */
+ public function getRootInternalPath() {
+ return $this->mount->getInternalPath($this->mount->getMountPoint());
+ }
}
diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php
index bd8343fa440..e9e142d0d4b 100644
--- a/lib/private/Files/Config/UserMountCache.php
+++ b/lib/private/Files/Config/UserMountCache.php
@@ -31,6 +31,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Config\ICachedMountInfo;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\Mount\IMountPoint;
+use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\ICache;
use OCP\IDBConnection;
@@ -187,7 +188,7 @@ class UserMountCache implements IUserMountCache {
private function dbRowToMountInfo(array $row) {
$user = $this->userManager->get($row['user_id']);
- return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id']);
+ return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id'], isset($row['path'])? $row['path']:'');
}
/**
@@ -197,8 +198,9 @@ class UserMountCache implements IUserMountCache {
public function getMountsForUser(IUser $user) {
if (!isset($this->mountsForUsers[$user->getUID()])) {
$builder = $this->connection->getQueryBuilder();
- $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
- ->from('mounts')
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
+ ->from('mounts', 'm')
+ ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
$rows = $query->execute()->fetchAll();
@@ -214,8 +216,9 @@ class UserMountCache implements IUserMountCache {
*/
public function getMountsForStorageId($numericStorageId) {
$builder = $this->connection->getQueryBuilder();
- $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
- ->from('mounts')
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
+ ->from('mounts', 'm')
+ ->innerJoin('m', 'filecache', 'f' , $builder->expr()->eq('m.root_id', 'f.fileid'))
->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
$rows = $query->execute()->fetchAll();
@@ -229,8 +232,9 @@ class UserMountCache implements IUserMountCache {
*/
public function getMountsForRootId($rootFileId) {
$builder = $this->connection->getQueryBuilder();
- $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id')
- ->from('mounts')
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
+ ->from('mounts', 'm')
+ ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
$rows = $query->execute()->fetchAll();
@@ -246,7 +250,7 @@ class UserMountCache implements IUserMountCache {
private function getCacheInfoFromFileId($fileId) {
if (!isset($this->cacheInfoCache[$fileId])) {
$builder = $this->connection->getQueryBuilder();
- $query = $builder->select('storage', 'path')
+ $query = $builder->select('storage', 'path', 'mimetype')
->from('filecache')
->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
@@ -254,7 +258,8 @@ class UserMountCache implements IUserMountCache {
if (is_array($row)) {
$this->cacheInfoCache[$fileId] = [
(int)$row['storage'],
- $row['path']
+ $row['path'],
+ (int)$row['mimetype']
];
} else {
throw new NotFoundException('File with id "' . $fileId . '" not found');
@@ -281,15 +286,10 @@ class UserMountCache implements IUserMountCache {
if ($fileId === $mount->getRootId()) {
return true;
}
- try {
- list(, $internalMountPath) = $this->getCacheInfoFromFileId($mount->getRootId());
- } catch (NotFoundException $e) {
- return false;
- }
+ $internalMountPath = $mount->getRootInternalPath();
return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
});
-
}
/**
diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php
index d835fea7f4c..113bb5a85c6 100644
--- a/lib/private/Files/Filesystem.php
+++ b/lib/private/Files/Filesystem.php
@@ -225,7 +225,7 @@ class Filesystem {
* @param int $priority
*/
public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
- if (self::$logWarningWhenAddingStorageWrapper) {
+ if (self::$logWarningWhenAddingStorageWrapper && $wrapperName !== 'readonly') {
\OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
'wrapper' => $wrapperName,
'app' => 'filesystem',
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index e67e4817e2a..288a02ef207 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -28,6 +28,7 @@ namespace OC\Files\Node;
use OC\DB\QueryBuilder\Literal;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\Files\Config\ICachedMountInfo;
use OCP\Files\FileInfo;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\NotFoundException;
@@ -41,7 +42,7 @@ class Folder extends Node implements \OCP\Files\Folder {
*/
public function getFullPath($path) {
if (!$this->isValidPath($path)) {
- throw new NotPermittedException();
+ throw new NotPermittedException('Invalid path');
}
return $this->path . $this->normalizePath($path);
}
@@ -83,7 +84,7 @@ class Folder extends Node implements \OCP\Files\Folder {
public function getDirectoryListing() {
$folderContent = $this->view->getDirectoryContent($this->path);
- return array_map(function(FileInfo $info) {
+ return array_map(function (FileInfo $info) {
if ($info->getMimetype() === 'httpd/unix-directory') {
return new Folder($this->root, $this->view, $info->getPath(), $info);
} else {
@@ -151,7 +152,7 @@ class Folder extends Node implements \OCP\Files\Folder {
$this->root->emit('\OC\Files', 'postCreate', array($node));
return $node;
} else {
- throw new NotPermittedException();
+ throw new NotPermittedException('No create permission for folder');
}
}
@@ -172,7 +173,7 @@ class Folder extends Node implements \OCP\Files\Folder {
$this->root->emit('\OC\Files', 'postCreate', array($node));
return $node;
} else {
- throw new NotPermittedException();
+ throw new NotPermittedException('No create permission for path');
}
}
@@ -253,7 +254,7 @@ class Folder extends Node implements \OCP\Files\Folder {
}
}
- return array_map(function(FileInfo $file) {
+ return array_map(function (FileInfo $file) {
return $this->createNode($file->getPath(), $file);
}, $files);
}
@@ -263,29 +264,48 @@ class Folder extends Node implements \OCP\Files\Folder {
* @return \OC\Files\Node\Node[]
*/
public function getById($id) {
+ $mountCache = $this->root->getUserMountCache();
+ $mountsContainingFile = $mountCache->getMountsForFileId((int)$id);
$mounts = $this->root->getMountsIn($this->path);
$mounts[] = $this->root->getMount($this->path);
- // reverse the array so we start with the storage this view is in
- // which is the most likely to contain the file we're looking for
- $mounts = array_reverse($mounts);
+ /** @var IMountPoint[] $folderMounts */
+ $folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
+ return $mountPoint->getMountPoint();
+ }, $mounts), $mounts);
+
+ /** @var ICachedMountInfo[] $mountsContainingFile */
+ $mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
+ return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
+ }));
- $nodes = array();
- foreach ($mounts as $mount) {
- /**
- * @var \OC\Files\Mount\MountPoint $mount
- */
- if ($mount->getStorage()) {
- $cache = $mount->getStorage()->getCache();
- $internalPath = $cache->getPathById($id);
- if (is_string($internalPath)) {
- $fullPath = $mount->getMountPoint() . $internalPath;
- if (!is_null($path = $this->getRelativePath($fullPath))) {
- $nodes[] = $this->get($path);
- }
- }
- }
+ if (count($mountsContainingFile) === 0) {
+ return [];
}
- return $nodes;
+
+ // we only need to get the cache info once, since all mounts we found point to the same storage
+
+ $mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
+ $cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
+ if (!$cacheEntry) {
+ return [];
+ }
+ // cache jails will hide the "true" internal path
+ $internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
+
+ $nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
+ $mount = $folderMounts[$cachedMountInfo->getMountPoint()];
+ $pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
+ $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
+ $absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
+ return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
+ $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
+ \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
+ ));
+ }, $mountsContainingFile);
+
+ return array_filter($nodes, function (Node $node) {
+ return $this->getRelativePath($node->getPath());
+ });
}
public function getFreeSpace() {
@@ -301,7 +321,7 @@ class Folder extends Node implements \OCP\Files\Folder {
$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
$this->exists = false;
} else {
- throw new NotPermittedException();
+ throw new NotPermittedException('No delete permission for path');
}
}
@@ -323,7 +343,7 @@ class Folder extends Node implements \OCP\Files\Folder {
$this->root->emit('\OC\Files', 'postWrite', array($targetNode));
return $targetNode;
} else {
- throw new NotPermittedException();
+ throw new NotPermittedException('No permission to copy to path');
}
}
@@ -346,7 +366,7 @@ class Folder extends Node implements \OCP\Files\Folder {
$this->path = $targetPath;
return $targetNode;
} else {
- throw new NotPermittedException();
+ throw new NotPermittedException('No permission to move to path');
}
}
diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php
index 007847fb513..0cda2c8b822 100644
--- a/lib/private/Files/Node/Root.php
+++ b/lib/private/Files/Node/Root.php
@@ -31,6 +31,7 @@ namespace OC\Files\Node;
use OC\Cache\CappedMemoryCache;
use OC\Files\Mount\Manager;
use OC\Files\Mount\MountPoint;
+use OCP\Files\Config\IUserMountCache;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OC\Hooks\PublicEmitter;
@@ -75,16 +76,23 @@ class Root extends Folder implements IRootFolder {
private $userFolderCache;
/**
+ * @var IUserMountCache
+ */
+ private $userMountCache;
+
+ /**
* @param \OC\Files\Mount\Manager $manager
* @param \OC\Files\View $view
* @param \OC\User\User|null $user
+ * @param IUserMountCache $userMountCache
*/
- public function __construct($manager, $view, $user) {
+ public function __construct($manager, $view, $user, IUserMountCache $userMountCache) {
parent::__construct($this, $view, '');
$this->mountManager = $manager;
$this->user = $user;
$this->emitter = new PublicEmitter();
$this->userFolderCache = new CappedMemoryCache();
+ $this->userMountCache = $userMountCache;
}
/**
@@ -361,4 +369,8 @@ class Root extends Folder implements IRootFolder {
public function clearCache() {
$this->userFolderCache = new CappedMemoryCache();
}
+
+ public function getUserMountCache() {
+ return $this->userMountCache;
+ }
}
diff --git a/lib/private/Files/SimpleFS/SimpleFile.php b/lib/private/Files/SimpleFS/SimpleFile.php
new file mode 100644
index 00000000000..5eadfd98b60
--- /dev/null
+++ b/lib/private/Files/SimpleFS/SimpleFile.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Files\SimpleFS;
+
+use OCP\Files\File;
+use OCP\Files\NotPermittedException;
+use OCP\Files\SimpleFS\ISimpleFile;
+
+class SimpleFile implements ISimpleFile {
+
+ /** @var File $file */
+ private $file;
+
+ /**
+ * File constructor.
+ *
+ * @param File $file
+ */
+ public function __construct(File $file) {
+ $this->file = $file;
+ }
+
+ /**
+ * Get the name
+ *
+ * @return string
+ */
+ public function getName() {
+ return $this->file->getName();
+ }
+
+ /**
+ * Get the size in bytes
+ *
+ * @return int
+ */
+ public function getSize() {
+ return $this->file->getSize();
+ }
+
+ /**
+ * Get the ETag
+ *
+ * @return string
+ */
+ public function getETag() {
+ return $this->file->getEtag();
+ }
+
+ /**
+ * Get the last modification time
+ *
+ * @return int
+ */
+ public function getMTime() {
+ return $this->file->getMTime();
+ }
+
+ /**
+ * Get the content
+ *
+ * @return string
+ */
+ public function getContent() {
+ return $this->file->getContent();
+ }
+
+ /**
+ * Overwrite the file
+ *
+ * @param string $data
+ * @throws NotPermittedException
+ */
+ public function putContent($data) {
+ $this->file->putContent($data);
+ }
+
+ /**
+ * Delete the file
+ *
+ * @throws NotPermittedException
+ */
+ public function delete() {
+ $this->file->delete();
+ }
+
+ /**
+ * Get the MimeType
+ *
+ * @return string
+ */
+ public function getMimeType() {
+ return $this->file->getMimeType();
+ }
+}
diff --git a/lib/private/Files/SimpleFS/SimpleFolder.php b/lib/private/Files/SimpleFS/SimpleFolder.php
new file mode 100644
index 00000000000..5b55fe0f157
--- /dev/null
+++ b/lib/private/Files/SimpleFS/SimpleFolder.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Files\SimpleFS;
+
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\Node;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFolder;
+
+class SimpleFolder implements ISimpleFolder {
+
+ /** @var Folder */
+ private $folder;
+
+ /**
+ * Folder constructor.
+ *
+ * @param Folder $folder
+ */
+ public function __construct(Folder $folder) {
+ $this->folder = $folder;
+ }
+
+ public function getName() {
+ return $this->folder->getName();
+ }
+
+ public function getDirectoryListing() {
+ $listing = $this->folder->getDirectoryListing();
+
+ $fileListing = array_map(function(Node $file) {
+ if ($file instanceof File) {
+ return new SimpleFile($file);
+ }
+ return null;
+ }, $listing);
+
+ $fileListing = array_filter($fileListing);
+
+ return array_values($fileListing);
+ }
+
+ public function delete() {
+ $this->folder->delete();
+ }
+
+ public function fileExists($name) {
+ return $this->folder->nodeExists($name);
+ }
+
+ public function getFile($name) {
+ $file = $this->folder->get($name);
+
+ if (!($file instanceof File)) {
+ throw new NotFoundException();
+ }
+
+ return new SimpleFile($file);
+ }
+
+ public function newFile($name) {
+ $file = $this->folder->newFile($name);
+
+ return new SimpleFile($file);
+ }
+}
diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php
index 63d3c004fd2..c975791295d 100644
--- a/lib/private/Files/Storage/Common.php
+++ b/lib/private/Files/Storage/Common.php
@@ -466,6 +466,10 @@ abstract class Common implements Storage, ILockingStorage {
* @return bool
*/
public function instanceOfStorage($class) {
+ if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') {
+ // FIXME Temporary fix to keep existing checks working
+ $class = '\OCA\Files_Sharing\SharedStorage';
+ }
return is_a($this, $class);
}
diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php
index 19674fc9413..4fe7dcafbbf 100644
--- a/lib/private/Files/Storage/Local.php
+++ b/lib/private/Files/Storage/Local.php
@@ -54,7 +54,12 @@ class Local extends \OC\Files\Storage\Common {
throw new \InvalidArgumentException('No data directory set for local storage');
}
$this->datadir = $arguments['datadir'];
- $this->realDataDir = rtrim(realpath($this->datadir), '/') . '/';
+ // some crazy code uses a local storage on root...
+ if ($this->datadir === '/') {
+ $this->realDataDir = $this->datadir;
+ } else {
+ $this->realDataDir = rtrim(realpath($this->datadir), '/') . '/';
+ }
if (substr($this->datadir, -1) !== '/') {
$this->datadir .= '/';
}
@@ -150,7 +155,7 @@ class Local extends \OC\Files\Storage\Common {
$fullPath = $this->getSourcePath($path);
if (PHP_INT_SIZE === 4) {
$helper = new \OC\LargeFileHelper;
- return $helper->getFilesize($fullPath);
+ return $helper->getFileSize($fullPath);
}
return filesize($fullPath);
}
@@ -168,8 +173,16 @@ class Local extends \OC\Files\Storage\Common {
}
public function filemtime($path) {
- clearstatcache($this->getSourcePath($path));
- return $this->file_exists($path) ? filemtime($this->getSourcePath($path)) : false;
+ $fullPath = $this->getSourcePath($path);
+ clearstatcache($fullPath);
+ if (!$this->file_exists($path)) {
+ return false;
+ }
+ if (PHP_INT_SIZE === 4) {
+ $helper = new \OC\LargeFileHelper();
+ return $helper->getFileMtime($fullPath);
+ }
+ return filemtime($fullPath);
}
public function touch($path, $mtime = null) {
diff --git a/lib/private/Files/Storage/Wrapper/PermissionsMask.php b/lib/private/Files/Storage/Wrapper/PermissionsMask.php
index 39375602c34..7bcb1087fef 100644
--- a/lib/private/Files/Storage/Wrapper/PermissionsMask.php
+++ b/lib/private/Files/Storage/Wrapper/PermissionsMask.php
@@ -78,6 +78,14 @@ class PermissionsMask extends Wrapper {
}
public function rename($path1, $path2) {
+ $p = strpos($path1, $path2);
+ if ($p === 0) {
+ $part = substr($path1, strlen($path2));
+ //This is a rename of the transfer file to the original file
+ if (strpos($part, '.ocTransferId') === 0) {
+ return $this->checkMask(Constants::PERMISSION_CREATE) and parent::rename($path1, $path2);
+ }
+ }
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($path1, $path2);
}
diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php
index c52b3394832..71b64d8c82c 100644
--- a/lib/private/Files/Storage/Wrapper/Wrapper.php
+++ b/lib/private/Files/Storage/Wrapper/Wrapper.php
@@ -483,6 +483,10 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage {
* @return bool
*/
public function instanceOfStorage($class) {
+ if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') {
+ // FIXME Temporary fix to keep existing checks working
+ $class = '\OCA\Files_Sharing\SharedStorage';
+ }
return is_a($this, $class) or $this->getWrapperStorage()->instanceOfStorage($class);
}
diff --git a/lib/private/Files/Stream/OC.php b/lib/private/Files/Stream/OC.php
deleted file mode 100644
index f415bc13b15..00000000000
--- a/lib/private/Files/Stream/OC.php
+++ /dev/null
@@ -1,154 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- *
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OC\Files\Stream;
-
-/**
- * a stream wrappers for ownCloud's virtual filesystem
- */
-class OC {
- /**
- * @var \OC\Files\View
- */
- static private $rootView;
-
- private $path;
-
- /**
- * @var resource
- */
- private $dirSource;
-
- /**
- * @var resource
- */
- private $fileSource;
- private $meta;
-
- private function setup(){
- if (!self::$rootView) {
- self::$rootView = new \OC\Files\View('');
- }
- }
-
- public function stream_open($path, $mode, $options, &$opened_path) {
- $this->setup();
- $path = substr($path, strlen('oc://'));
- $this->path = $path;
- $this->fileSource = self::$rootView->fopen($path, $mode);
- if (is_resource($this->fileSource)) {
- $this->meta = stream_get_meta_data($this->fileSource);
- }
- return is_resource($this->fileSource);
- }
-
- public function stream_seek($offset, $whence = SEEK_SET) {
- return fseek($this->fileSource, $offset, $whence) === 0;
- }
-
- public function stream_tell() {
- return ftell($this->fileSource);
- }
-
- public function stream_read($count) {
- return fread($this->fileSource, $count);
- }
-
- public function stream_write($data) {
- return fwrite($this->fileSource, $data);
- }
-
- public function stream_set_option($option, $arg1, $arg2) {
- switch ($option) {
- case STREAM_OPTION_BLOCKING:
- stream_set_blocking($this->fileSource, $arg1);
- break;
- case STREAM_OPTION_READ_TIMEOUT:
- stream_set_timeout($this->fileSource, $arg1, $arg2);
- break;
- case STREAM_OPTION_WRITE_BUFFER:
- stream_set_write_buffer($this->fileSource, $arg1, $arg2);
- }
- }
-
- public function stream_stat() {
- return fstat($this->fileSource);
- }
-
- public function stream_lock($mode) {
- flock($this->fileSource, $mode);
- }
-
- public function stream_flush() {
- return fflush($this->fileSource);
- }
-
- public function stream_eof() {
- return feof($this->fileSource);
- }
-
- public function url_stat($path) {
- $this->setup();
- $path = substr($path, strlen('oc://'));
- if (self::$rootView->file_exists($path)) {
- return self::$rootView->stat($path);
- } else {
- return false;
- }
- }
-
- public function stream_close() {
- fclose($this->fileSource);
- }
-
- public function unlink($path) {
- $this->setup();
- $path = substr($path, strlen('oc://'));
- return self::$rootView->unlink($path);
- }
-
- public function dir_opendir($path, $options) {
- $this->setup();
- $path = substr($path, strlen('oc://'));
- $this->path = $path;
- $this->dirSource = self::$rootView->opendir($path);
- if (is_resource($this->dirSource)) {
- $this->meta = stream_get_meta_data($this->dirSource);
- }
- return is_resource($this->dirSource);
- }
-
- public function dir_readdir() {
- return readdir($this->dirSource);
- }
-
- public function dir_closedir() {
- closedir($this->dirSource);
- }
-
- public function dir_rewinddir() {
- rewinddir($this->dirSource);
- }
-}
diff --git a/lib/private/Files/Type/Detection.php b/lib/private/Files/Type/Detection.php
index 66ef0dd2aab..84d727ebb0e 100644
--- a/lib/private/Files/Type/Detection.php
+++ b/lib/private/Files/Type/Detection.php
@@ -166,9 +166,11 @@ class Detection implements IMimeTypeDetector {
public function detectPath($path) {
$this->loadMappings();
- if (strpos($path, '.')) {
+ $fileName = basename($path);
+ // note: leading dot doesn't qualify as extension
+ if (strpos($fileName, '.') > 0) {
//try to guess the type by the file extension
- $extension = strtolower(strrchr(basename($path), "."));
+ $extension = strtolower(strrchr($fileName, '.'));
$extension = substr($extension, 1); //remove leading .
return (isset($this->mimetypes[$extension]) && isset($this->mimetypes[$extension][0]))
? $this->mimetypes[$extension][0]
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index fa6ba20c342..f36e2c2c64f 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -1357,7 +1357,7 @@ class View {
$subStorage = $mount->getStorage();
if ($subStorage) {
// exclude shared storage ?
- if ($extOnly && $subStorage instanceof \OC\Files\Storage\Shared) {
+ if ($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage) {
continue;
}
$subCache = $subStorage->getCache('');
@@ -1806,13 +1806,15 @@ class View {
throw new InvalidPathException($l10n->t('Dot files are not allowed'));
}
- // verify database - e.g. mysql only 3-byte chars
- if (preg_match('%(?:
+ if (!\OC::$server->getDatabaseConnection()->supports4ByteText()) {
+ // verify database - e.g. mysql only 3-byte chars
+ if (preg_match('%(?:
\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)%xs', $fileName)) {
- throw new InvalidPathException($l10n->t('4-byte characters are not supported in file names'));
+ throw new InvalidPathException($l10n->t('4-byte characters are not supported in file names'));
+ }
}
try {
diff --git a/lib/private/Installer.php b/lib/private/Installer.php
index 3d8a923417a..009df790585 100644
--- a/lib/private/Installer.php
+++ b/lib/private/Installer.php
@@ -614,7 +614,7 @@ class Installer {
}
$codeChecker = new CodeChecker(new PrivateCheck(new EmptyCheck()));
- $errors = $codeChecker->analyseFolder($folder);
+ $errors = $codeChecker->analyseFolder(basename($folder), $folder);
return empty($errors);
}
diff --git a/lib/private/IntegrityCheck/Checker.php b/lib/private/IntegrityCheck/Checker.php
index 1db20772b4e..102fe42a99d 100644
--- a/lib/private/IntegrityCheck/Checker.php
+++ b/lib/private/IntegrityCheck/Checker.php
@@ -195,7 +195,7 @@ class Checker {
copy($this->environmentHelper->getServerRoot() . '/.htaccess', $tmpFolder . '/.htaccess');
copy($this->environmentHelper->getServerRoot() . '/.user.ini', $tmpFolder . '/.user.ini');
\OC_Files::setUploadLimit(
- \OCP\Util::computerFileSize('513MB'),
+ \OCP\Util::computerFileSize('511MB'),
[
'.htaccess' => $tmpFolder . '/.htaccess',
'.user.ini' => $tmpFolder . '/.user.ini',
diff --git a/lib/private/L10N/Factory.php b/lib/private/L10N/Factory.php
index 91233a0c4a7..8aad395065c 100644
--- a/lib/private/L10N/Factory.php
+++ b/lib/private/L10N/Factory.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ * @copyright 2016 Lukas Reschke <lukas@statuscode.ch>
*
* @author Bart Visscher <bartv@thisnet.nl>
* @author Joas Schilling <coding@schilljs.com>
@@ -288,6 +289,27 @@ class Factory implements IFactory {
}
/**
+ * Checks if $sub is a subdirectory of $parent
+ *
+ * @param string $sub
+ * @param string $parent
+ * @return bool
+ */
+ private function isSubDirectory($sub, $parent) {
+ // Check whether $sub contains no ".."
+ if(strpos($sub, '..') !== false) {
+ return false;
+ }
+
+ // Check whether $sub is a subdirectory of $parent
+ if (strpos($sub, $parent) === 0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* Get a list of language files that should be loaded
*
* @param string $app
@@ -302,10 +324,10 @@ class Factory implements IFactory {
$i18nDir = $this->findL10nDir($app);
$transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
- if ((\OC_Helper::isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
- || \OC_Helper::isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
- || \OC_Helper::isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
- || \OC_Helper::isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
+ if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
+ || $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
+ || $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
+ || $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
)
&& file_exists($transFile)) {
// load the translations file
diff --git a/lib/private/LargeFileHelper.php b/lib/private/LargeFileHelper.php
index 9d0fe864033..9f18a6acd6b 100644
--- a/lib/private/LargeFileHelper.php
+++ b/lib/private/LargeFileHelper.php
@@ -1,6 +1,7 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
*
* @author Andreas Fischer <bantu@owncloud.com>
* @author Lukas Reschke <lukas@statuscode.ch>
@@ -51,7 +52,7 @@ class LargeFileHelper {
public function __construct() {
$pow_2_53 = floatval(self::POW_2_53_MINUS_1) + 1.0;
if ($this->formatUnsignedInteger($pow_2_53) !== self::POW_2_53) {
- throw new \RunTimeException(
+ throw new \RuntimeException(
'This class assumes floats to be double precision or "better".'
);
}
@@ -98,10 +99,6 @@ class LargeFileHelper {
if (!is_null($fileSize)) {
return $fileSize;
}
- $fileSize = $this->getFileSizeViaCOM($filename);
- if (!is_null($fileSize)) {
- return $fileSize;
- }
$fileSize = $this->getFileSizeViaExec($filename);
if (!is_null($fileSize)) {
return $fileSize;
@@ -154,12 +151,6 @@ class LargeFileHelper {
$result = $this->exec("stat -c %s $arg");
} else if (strpos($os, 'bsd') !== false || strpos($os, 'darwin') !== false) {
$result = $this->exec("stat -f %z $arg");
- } else if (strpos($os, 'win') !== false) {
- $result = $this->exec("for %F in ($arg) do @echo %~zF");
- if (is_null($result)) {
- // PowerShell
- $result = $this->exec("(Get-Item $arg).length");
- }
}
return $result;
}
@@ -187,6 +178,23 @@ class LargeFileHelper {
return $result;
}
+ /**
+ * Returns the current mtime for $fullPath
+ *
+ * @param string $fullPath
+ * @return int
+ */
+ public function getFileMtime($fullPath) {
+ if (\OC_Helper::is_function_enabled('exec')) {
+ $os = strtolower(php_uname('s'));
+ if (strpos($os, 'linux') !== false) {
+ return $this->exec('stat -c %Y ' . escapeshellarg($fullPath));
+ }
+ }
+
+ return filemtime($fullPath);
+ }
+
protected function exec($cmd) {
$result = trim(exec($cmd));
return ctype_digit($result) ? 0 + $result : null;
diff --git a/lib/private/Log.php b/lib/private/Log.php
index 3e0734965b0..ef1b70d3cb9 100644
--- a/lib/private/Log.php
+++ b/lib/private/Log.php
@@ -233,7 +233,7 @@ class Log implements ILogger {
* @return void
*/
public function log($level, $message, array $context = array()) {
- $minLevel = min($this->config->getValue('loglevel', Util::WARN), Util::ERROR);
+ $minLevel = min($this->config->getValue('loglevel', Util::WARN), Util::FATAL);
$logCondition = $this->config->getValue('log.condition', []);
array_walk($context, [$this->normalizer, 'format']);
@@ -277,7 +277,7 @@ class Log implements ILogger {
$request = \OC::$server->getRequest();
// if token is found in the request change set the log condition to satisfied
- if($request && hash_equals($logCondition['shared_secret'], $request->getParam('log_secret'))) {
+ if($request && hash_equals($logCondition['shared_secret'], $request->getParam('log_secret', ''))) {
$this->logConditionSatisfied = true;
}
}
diff --git a/lib/private/Log/File.php b/lib/private/Log/File.php
index a406dd83952..904aa1d93f1 100644
--- a/lib/private/Log/File.php
+++ b/lib/private/Log/File.php
@@ -96,11 +96,12 @@ class File {
$time = $time->format($format);
$url = ($request->getRequestUri() !== '') ? $request->getRequestUri() : '--';
$method = is_string($request->getMethod()) ? $request->getMethod() : '--';
- if(\OC::$server->getConfig()->getSystemValue('installed', false)) {
+ if($config->getValue('installed', false)) {
$user = (\OC_User::getUser()) ? \OC_User::getUser() : '--';
} else {
$user = '--';
}
+ $version = $config->getValue('version', '');
$entry = compact(
'reqId',
'remoteAddr',
@@ -110,7 +111,8 @@ class File {
'time',
'method',
'url',
- 'user'
+ 'user',
+ 'version'
);
$entry = json_encode($entry);
$handle = @fopen(self::$logFile, 'a');
diff --git a/lib/private/Notification/Notification.php b/lib/private/Notification/Notification.php
index 9b5877a3058..7bf4b9a74cf 100644
--- a/lib/private/Notification/Notification.php
+++ b/lib/private/Notification/Notification.php
@@ -242,7 +242,7 @@ class Notification implements INotification {
/**
* @param string $subject
* @return $this
- * @throws \InvalidArgumentException if the subject are invalid
+ * @throws \InvalidArgumentException if the subject is invalid
* @since 8.2.0
*/
public function setParsedSubject($subject) {
@@ -300,7 +300,7 @@ class Notification implements INotification {
/**
* @param string $message
* @return $this
- * @throws \InvalidArgumentException if the message are invalid
+ * @throws \InvalidArgumentException if the message is invalid
* @since 8.2.0
*/
public function setParsedMessage($message) {
@@ -322,7 +322,7 @@ class Notification implements INotification {
/**
* @param string $link
* @return $this
- * @throws \InvalidArgumentException if the link are invalid
+ * @throws \InvalidArgumentException if the link is invalid
* @since 8.2.0
*/
public function setLink($link) {
@@ -342,6 +342,28 @@ class Notification implements INotification {
}
/**
+ * @param string $icon
+ * @return $this
+ * @throws \InvalidArgumentException if the icon is invalid
+ * @since 9.2.0
+ */
+ public function setIcon($icon) {
+ if (!is_string($icon) || $icon === '' || isset($icon[4000])) {
+ throw new \InvalidArgumentException('The given icon is invalid');
+ }
+ $this->icon = $icon;
+ return $this;
+ }
+
+ /**
+ * @return string
+ * @since 9.2.0
+ */
+ public function getIcon() {
+ return $this->icon;
+ }
+
+ /**
* @return IAction
* @since 8.2.0
*/
@@ -352,7 +374,7 @@ class Notification implements INotification {
/**
* @param IAction $action
* @return $this
- * @throws \InvalidArgumentException if the action are invalid
+ * @throws \InvalidArgumentException if the action is invalid
* @since 8.2.0
*/
public function addAction(IAction $action) {
@@ -383,7 +405,7 @@ class Notification implements INotification {
/**
* @param IAction $action
* @return $this
- * @throws \InvalidArgumentException if the action are invalid
+ * @throws \InvalidArgumentException if the action is invalid
* @since 8.2.0
*/
public function addParsedAction(IAction $action) {
diff --git a/lib/private/Preview.php b/lib/private/Preview.php
index 67838a8d4a3..ccaec738caf 100644
--- a/lib/private/Preview.php
+++ b/lib/private/Preview.php
@@ -131,7 +131,7 @@ class Preview {
$this->setFile($file);
$this->setMaxX((int)$maxX);
$this->setMaxY((int)$maxY);
- $this->setScalingUp($scalingUp);
+ $this->setScalingup($scalingUp);
$this->preview = null;
@@ -791,6 +791,7 @@ class Preview {
* @param null|string $mimeTypeForHeaders the media type to use when sending back the reply
*
* @throws NotFoundException
+ * @throws PreviewNotAvailableException
*/
public function showPreview($mimeTypeForHeaders = null) {
// Check if file is valid
@@ -1172,6 +1173,7 @@ class Preview {
/**
* Defines the media icon, for the media type of the original file, as the preview
+ * @throws PreviewNotAvailableException
*/
private function getMimeIcon() {
$image = new \OC_Image();
@@ -1181,6 +1183,10 @@ class Preview {
} else {
$mimeIconServerPath = str_replace(\OC::$WEBROOT, \OC::$SERVERROOT, $mimeIconWebPath);
}
+ // we can't load SVGs into an image
+ if (substr($mimeIconWebPath, -4) === '.svg') {
+ throw new PreviewNotAvailableException('SVG mimetype cannot be rendered');
+ }
$image->loadFromFile($mimeIconServerPath);
$this->preview = $image;
diff --git a/lib/private/PreviewNotAvailableException.php b/lib/private/PreviewNotAvailableException.php
new file mode 100644
index 00000000000..7d92e860629
--- /dev/null
+++ b/lib/private/PreviewNotAvailableException.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Morris Jobke <hey@morrisjobke.de>
+ *
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC;
+
+class PreviewNotAvailableException extends \Exception {
+}
diff --git a/lib/private/Repair.php b/lib/private/Repair.php
index cd23f5cb806..7a5ef9fbd9e 100644
--- a/lib/private/Repair.php
+++ b/lib/private/Repair.php
@@ -35,6 +35,8 @@ use OC\Repair\AvatarPermissions;
use OC\Repair\CleanTags;
use OC\Repair\Collation;
use OC\Repair\DropOldJobs;
+use OC\Repair\MoveUpdaterStepFile;
+use OC\Repair\NC11\MoveAvatars;
use OC\Repair\OldGroupMembershipShares;
use OC\Repair\RemoveGetETagEntries;
use OC\Repair\RemoveOldShares;
@@ -127,6 +129,7 @@ class Repair implements IOutput{
*/
public static function getRepairSteps() {
return [
+ new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->getDatabaseConnection(), false),
new RepairMimeTypes(\OC::$server->getConfig()),
new RepairLegacyStorages(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
new AssetCache(),
@@ -147,6 +150,11 @@ class Repair implements IOutput{
\OC::$server->getUserManager(),
\OC::$server->getGroupManager()
),
+ new MoveUpdaterStepFile(\OC::$server->getConfig()),
+ new MoveAvatars(
+ \OC::$server->getJobList(),
+ \OC::$server->getSystemConfig()
+ ),
];
}
@@ -172,7 +180,7 @@ class Repair implements IOutput{
$connection = \OC::$server->getDatabaseConnection();
$steps = [
new InnoDB(),
- new Collation(\OC::$server->getConfig(), $connection),
+ new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), $connection, true),
new SqliteAutoincrement($connection),
new SearchLuceneTables(),
];
diff --git a/lib/private/Repair/Collation.php b/lib/private/Repair/Collation.php
index 74c4ca2e6ac..54de1a719bd 100644
--- a/lib/private/Repair/Collation.php
+++ b/lib/private/Repair/Collation.php
@@ -24,28 +24,38 @@
namespace OC\Repair;
+use Doctrine\DBAL\Exception\DriverException;
use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\ILogger;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class Collation implements IRepairStep {
- /**
- * @var \OCP\IConfig
- */
+ /** @var IConfig */
protected $config;
- /**
- * @var \OC\DB\Connection
- */
+ /** @var ILogger */
+ protected $logger;
+
+ /** @var IDBConnection */
protected $connection;
+ /** @var bool */
+ protected $ignoreFailures;
+
/**
- * @param \OCP\IConfig $config
- * @param \OC\DB\Connection $connection
+ * @param IConfig $config
+ * @param ILogger $logger
+ * @param IDBConnection $connection
+ * @param bool $ignoreFailures
*/
- public function __construct($config, $connection) {
+ public function __construct(IConfig $config, ILogger $logger, IDBConnection $connection, $ignoreFailures) {
$this->connection = $connection;
$this->config = $config;
+ $this->logger = $logger;
+ $this->ignoreFailures = $ignoreFailures;
}
public function getName() {
@@ -61,11 +71,21 @@ class Collation implements IRepairStep {
return;
}
+ $characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
+
$tables = $this->getAllNonUTF8BinTables($this->connection);
foreach ($tables as $table) {
$output->info("Change collation for $table ...");
- $query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;');
- $query->execute();
+ $query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET ' . $characterSet . ' COLLATE ' . $characterSet . '_bin;');
+ try {
+ $query->execute();
+ } catch (DriverException $e) {
+ // Just log this
+ $this->logger->logException($e);
+ if (!$this->ignoreFailures) {
+ throw $e;
+ }
+ }
}
}
@@ -75,11 +95,12 @@ class Collation implements IRepairStep {
*/
protected function getAllNonUTF8BinTables($connection) {
$dbName = $this->config->getSystemValue("dbname");
+ $characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
$rows = $connection->fetchAll(
"SELECT DISTINCT(TABLE_NAME) AS `table`" .
" FROM INFORMATION_SCHEMA . COLUMNS" .
" WHERE TABLE_SCHEMA = ?" .
- " AND (COLLATION_NAME <> 'utf8_bin' OR CHARACTER_SET_NAME <> 'utf8')" .
+ " AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" .
" AND TABLE_NAME LIKE \"*PREFIX*%\"",
array($dbName)
);
diff --git a/lib/private/Repair/MoveUpdaterStepFile.php b/lib/private/Repair/MoveUpdaterStepFile.php
new file mode 100644
index 00000000000..fabaff40d24
--- /dev/null
+++ b/lib/private/Repair/MoveUpdaterStepFile.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Morris Jobke <hey@morrisjobke.de>
+ *
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Repair;
+
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class MoveUpdaterStepFile implements IRepairStep {
+
+ /** @var \OCP\IConfig */
+ protected $config;
+
+ /**
+ * @param \OCP\IConfig $config
+ */
+ public function __construct($config) {
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Move .step file of updater to backup location';
+ }
+
+ public function run(IOutput $output) {
+
+ $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT);
+ $instanceId = $this->config->getSystemValue('instanceid', null);
+
+ if(!is_string($instanceId) || empty($instanceId)) {
+ return;
+ }
+
+ $updaterFolderPath = $dataDir . '/updater-' . $instanceId;
+ $stepFile = $updaterFolderPath . '/.step';
+ if(file_exists($stepFile)) {
+ $output->info('.step file exists');
+
+ $previousStepFile = $updaterFolderPath . '/.step-previous-update';
+
+ // cleanup
+ if(file_exists($previousStepFile)) {
+ if(\OC_Helper::rmdirr($previousStepFile)) {
+ $output->info('.step-previous-update removed');
+ } else {
+ $output->info('.step-previous-update can\'t be removed - abort move of .step file');
+ return;
+ }
+ }
+
+ // move step file
+ if(rename($stepFile, $previousStepFile)) {
+ $output->info('.step file moved to .step-previous-update');
+ } else {
+ $output->warning('.step file can\'t be moved');
+ }
+ }
+ }
+}
+
diff --git a/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php b/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php
new file mode 100644
index 00000000000..993235146c9
--- /dev/null
+++ b/lib/private/Repair/NC11/MoveAvatarBackgroundJob.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Repair\NC11;
+
+use OC\BackgroundJob\QueuedJob;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\IAppData;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\ILogger;
+use OCP\IUser;
+use OCP\IUserManager;
+
+class MoveAvatarsBackgroundJob extends QueuedJob {
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ /** @var IAppData */
+ private $appData;
+
+ /** @var ILogger */
+ private $logger;
+
+ /**
+ * MoveAvatars constructor.
+ */
+ public function __construct() {
+ $this->userManager = \OC::$server->getUserManager();
+ $this->rootFolder = \OC::$server->getRootFolder();
+ $this->logger = \OC::$server->getLogger();
+ $this->appData = \OC::$server->getAppDataDir('avatar');
+ }
+
+ public function run($arguments) {
+ $this->logger->info('Started migrating avatars to AppData folder');
+ $this->moveAvatars();
+ $this->logger->info('All avatars migrated to AppData folder');
+ }
+
+ private function moveAvatars() {
+ $counter = 0;
+ $this->userManager->callForAllUsers(function (IUser $user) use ($counter) {
+ if ($user->getLastLogin() !== 0) {
+ $uid = $user->getUID();
+
+ \OC\Files\Filesystem::initMountPoints($uid);
+ /** @var Folder $userFolder */
+ $userFolder = $this->rootFolder->get($uid);
+
+ try {
+ $userData = $this->appData->getFolder($uid);
+ } catch (NotFoundException $e) {
+ $userData = $this->appData->newFolder($uid);
+ }
+
+
+ $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/';
+ $avatars = $userFolder->getDirectoryListing();
+
+ foreach ($avatars as $avatar) {
+ /** @var File $avatar */
+ if (preg_match($regex, $avatar->getName())) {
+ /*
+ * This is not the most effective but it is the most abstract way
+ * to handle this. Avatars should be small anyways.
+ */
+ $newAvatar = $userData->newFile($avatar->getName());
+ $newAvatar->putContent($avatar->getContent());
+ $avatar->delete();
+ }
+ }
+ }
+ $counter++;
+ if ($counter % 100) {
+ $this->logger->info('{amount} avatars migrated', ['amount' => $counter]);
+ }
+ });
+ }
+}
diff --git a/lib/private/Repair/NC11/MoveAvatars.php b/lib/private/Repair/NC11/MoveAvatars.php
new file mode 100644
index 00000000000..44402b1be4f
--- /dev/null
+++ b/lib/private/Repair/NC11/MoveAvatars.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Repair\NC11;
+
+use OC\SystemConfig;
+use OCP\BackgroundJob\IJobList;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class MoveAvatars implements IRepairStep {
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var SystemConfig */
+ private $systemConfig;
+
+ /**
+ * MoveAvatars constructor.
+ *
+ * @param IJobList $jobList
+ * @param SystemConfig $systemConfig
+ */
+ public function __construct(IJobList $jobList,
+ SystemConfig $systemConfig) {
+ $this->jobList = $jobList;
+ $this->systemConfig = $systemConfig;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return 'Add mover avatar background job';
+ }
+
+ public function run(IOutput $output) {
+ if ($this->systemConfig->getValue('enable_avatars', true) === false) {
+ $output->info('Avatars are disabled');
+ } else {
+ $this->jobList->add(MoveAvatarsBackgroundJob::class);
+ }
+ }
+}
diff --git a/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php b/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php
new file mode 100644
index 00000000000..e6a39b12a42
--- /dev/null
+++ b/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Security\CSP;
+
+use OC\Security\CSRF\CsrfTokenManager;
+use OCP\IRequest;
+
+/**
+ * @package OC\Security\CSP
+ */
+class ContentSecurityPolicyNonceManager {
+ /** @var CsrfTokenManager */
+ private $csrfTokenManager;
+ /** @var IRequest */
+ private $request;
+ /** @var string */
+ private $nonce = '';
+
+ /**
+ * @param CsrfTokenManager $csrfTokenManager
+ * @param IRequest $request
+ */
+ public function __construct(CsrfTokenManager $csrfTokenManager,
+ IRequest $request) {
+ $this->csrfTokenManager = $csrfTokenManager;
+ $this->request = $request;
+ }
+
+ /**
+ * Returns the current CSP nounce
+ *
+ * @return string
+ */
+ public function getNonce() {
+ if($this->nonce === '') {
+ $this->nonce = base64_encode($this->csrfTokenManager->getToken()->getEncryptedValue());
+ }
+
+ return $this->nonce;
+ }
+
+ /**
+ * Check if the browser supports CSP v3
+ *
+ * @return bool
+ */
+ public function browserSupportsCspV3() {
+ $browserWhitelist = [
+ // Chrome 40+
+ '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[4-9][0-9].[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+$/',
+ // Firefox 45+
+ '/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/(4[5-9]|[5-9][0-9])\.[0-9.]+$/',
+ // Safari 10+
+ '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/1[0-9.]+ Safari\/[0-9.A-Z]+$/',
+ ];
+
+ if($this->request->isUserAgent($browserWhitelist)) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/lib/private/Security/CSRF/CsrfToken.php b/lib/private/Security/CSRF/CsrfToken.php
index bf61e339f77..dce9a83b727 100644
--- a/lib/private/Security/CSRF/CsrfToken.php
+++ b/lib/private/Security/CSRF/CsrfToken.php
@@ -33,6 +33,8 @@ namespace OC\Security\CSRF;
class CsrfToken {
/** @var string */
private $value;
+ /** @var string */
+ private $encryptedValue = '';
/**
* @param string $value Value of the token. Can be encrypted or not encrypted.
@@ -48,8 +50,12 @@ class CsrfToken {
* @return string
*/
public function getEncryptedValue() {
- $sharedSecret = base64_encode(random_bytes(strlen($this->value)));
- return base64_encode($this->value ^ $sharedSecret) .':'.$sharedSecret;
+ if($this->encryptedValue === '') {
+ $sharedSecret = base64_encode(random_bytes(strlen($this->value)));
+ $this->encryptedValue = base64_encode($this->value ^ $sharedSecret) . ':' . $sharedSecret;
+ }
+
+ return $this->encryptedValue;
}
/**
diff --git a/lib/private/Security/CSRF/CsrfTokenManager.php b/lib/private/Security/CSRF/CsrfTokenManager.php
index d621cc2c29f..b43ca3d3679 100644
--- a/lib/private/Security/CSRF/CsrfTokenManager.php
+++ b/lib/private/Security/CSRF/CsrfTokenManager.php
@@ -34,6 +34,8 @@ class CsrfTokenManager {
private $tokenGenerator;
/** @var SessionStorage */
private $sessionStorage;
+ /** @var CsrfToken|null */
+ private $csrfToken = null;
/**
* @param CsrfTokenGenerator $tokenGenerator
@@ -51,6 +53,10 @@ class CsrfTokenManager {
* @return CsrfToken
*/
public function getToken() {
+ if(!is_null($this->csrfToken)) {
+ return $this->csrfToken;
+ }
+
if($this->sessionStorage->hasToken()) {
$value = $this->sessionStorage->getToken();
} else {
@@ -58,7 +64,8 @@ class CsrfTokenManager {
$this->sessionStorage->setToken($value);
}
- return new CsrfToken($value);
+ $this->csrfToken = new CsrfToken($value);
+ return $this->csrfToken;
}
/**
@@ -69,13 +76,15 @@ class CsrfTokenManager {
public function refreshToken() {
$value = $this->tokenGenerator->generateToken();
$this->sessionStorage->setToken($value);
- return new CsrfToken($value);
+ $this->csrfToken = new CsrfToken($value);
+ return $this->csrfToken;
}
/**
* Remove the current token from the storage.
*/
public function removeToken() {
+ $this->csrfToken = null;
$this->sessionStorage->removeToken();
}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 494387ab6ca..21ec311401d 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -73,6 +73,7 @@ use OC\Security\Bruteforce\Throttler;
use OC\Security\CertificateManager;
use OC\Security\CSP\ContentSecurityPolicyManager;
use OC\Security\Crypto;
+use OC\Security\CSP\ContentSecurityPolicyNonceManager;
use OC\Security\CSRF\CsrfTokenGenerator;
use OC\Security\CSRF\CsrfTokenManager;
use OC\Security\CSRF\TokenStorage\SessionStorage;
@@ -175,10 +176,10 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService('SystemTagObjectMapper', function (Server $c) {
return $c->query('SystemTagManagerFactory')->getObjectMapper();
});
- $this->registerService('RootFolder', function () {
+ $this->registerService('RootFolder', function (Server $c) {
$manager = \OC\Files\Filesystem::getMountManager(null);
$view = new View();
- $root = new Root($manager, $view, null);
+ $root = new Root($manager, $view, null, $c->getUserMountCache());
$connector = new HookConnector($root, $view);
$connector->viewToNode();
return $root;
@@ -359,7 +360,7 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService('AvatarManager', function (Server $c) {
return new AvatarManager(
$c->getUserManager(),
- $c->getRootFolder(),
+ $c->getAppDataDir('avatar'),
$c->getL10N('lib'),
$c->getLogger(),
$c->getConfig()
@@ -407,8 +408,8 @@ class Server extends ServerContainer implements IServerContainer {
return new CredentialsManager($c->getCrypto(), $c->getDatabaseConnection());
});
$this->registerService('DatabaseConnection', function (Server $c) {
- $factory = new \OC\DB\ConnectionFactory();
$systemConfig = $c->getSystemConfig();
+ $factory = new \OC\DB\ConnectionFactory($c->getConfig());
$type = $systemConfig->getValue('dbtype', 'sqlite');
if (!$factory->isValidType($type)) {
throw new \OC\DatabaseException('Invalid database type');
@@ -708,6 +709,12 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService('ContentSecurityPolicyManager', function (Server $c) {
return new ContentSecurityPolicyManager();
});
+ $this->registerService('ContentSecurityPolicyNonceManager', function(Server $c) {
+ return new ContentSecurityPolicyNonceManager(
+ $c->getCsrfTokenManager(),
+ $c->getRequest()
+ );
+ });
$this->registerService('ShareManager', function(Server $c) {
$config = $c->getConfig();
$factoryClass = $config->getSystemValue('sharing.managerFactory', '\OC\Share20\ProviderFactory');
@@ -742,6 +749,12 @@ class Server extends ServerContainer implements IServerContainer {
);
return $manager;
});
+ $this->registerService(\OC\Files\AppData\Factory::class, function (Server $c) {
+ return new \OC\Files\AppData\Factory(
+ $c->getRootFolder(),
+ $c->getSystemConfig()
+ );
+ });
}
/**
@@ -876,6 +889,7 @@ class Server extends ServerContainer implements IServerContainer {
* Returns an app-specific view in ownClouds data directory
*
* @return \OCP\Files\Folder
+ * @deprecated since 9.2.0 use IAppData
*/
public function getAppFolder() {
$dir = '/' . \OC_App::getCurrentApp();
@@ -1399,6 +1413,13 @@ class Server extends ServerContainer implements IServerContainer {
}
/**
+ * @return ContentSecurityPolicyNonceManager
+ */
+ public function getContentSecurityPolicyNonceManager() {
+ return $this->query('ContentSecurityPolicyNonceManager');
+ }
+
+ /**
* Not a public API as of 8.2, wait for 9.0
*
* @return \OCA\Files_External\Service\BackendService
@@ -1456,4 +1477,13 @@ class Server extends ServerContainer implements IServerContainer {
public function getSettingsManager() {
return $this->query('SettingsManager');
}
+
+ /**
+ * @return \OCP\Files\IAppData
+ */
+ public function getAppDataDir($app) {
+ /** @var \OC\Files\AppData\Factory $factory */
+ $factory = $this->query(\OC\Files\AppData\Factory::class);
+ return $factory->get($app);
+ }
}
diff --git a/lib/private/Setup.php b/lib/private/Setup.php
index 3b3a57c3e96..4c72fbc9623 100644
--- a/lib/private/Setup.php
+++ b/lib/private/Setup.php
@@ -410,6 +410,7 @@ class Setup {
/**
* Append the correct ErrorDocument path for Apache hosts
+ * @return bool True when success, False otherwise
*/
public static function updateHtaccess() {
$config = \OC::$server->getConfig();
@@ -418,7 +419,7 @@ class Setup {
if(\OC::$CLI) {
$webRoot = $config->getSystemValue('overwrite.cli.url', '');
if($webRoot === '') {
- return;
+ return false;
}
$webRoot = parse_url($webRoot, PHP_URL_PATH);
$webRoot = rtrim($webRoot, '/');
@@ -472,9 +473,10 @@ class Setup {
if ($content !== '') {
//suppress errors in case we don't have permissions for it
- @file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent.$content . "\n");
+ return (bool) @file_put_contents($setupHelper->pathToHtaccess(), $htaccessContent.$content . "\n");
}
+ return false;
}
public static function protectDataDirectory() {
diff --git a/lib/private/Setup/AbstractDatabase.php b/lib/private/Setup/AbstractDatabase.php
index 310f74d4c0c..47c3e5ee1c6 100644
--- a/lib/private/Setup/AbstractDatabase.php
+++ b/lib/private/Setup/AbstractDatabase.php
@@ -134,7 +134,7 @@ abstract class AbstractDatabase {
}
$connectionParams = array_merge($connectionParams, $configOverwrite);
- $cf = new ConnectionFactory();
+ $cf = new ConnectionFactory($this->config);
return $cf->getConnection($this->config->getSystemValue('dbtype', 'sqlite'), $connectionParams);
}
diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php
index 4ad6926c2d7..c022616d8b3 100644
--- a/lib/private/Setup/MySQL.php
+++ b/lib/private/Setup/MySQL.php
@@ -58,8 +58,9 @@ class MySQL extends AbstractDatabase {
try{
$name = $this->dbName;
$user = $this->dbUser;
- //we can't use OC_BD functions here because we need to connect as the administrative user.
- $query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET utf8 COLLATE utf8_bin;";
+ //we can't use OC_DB functions here because we need to connect as the administrative user.
+ $characterSet = \OC::$server->getSystemConfig()->getValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
+ $query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET $characterSet COLLATE ${characterSet}_bin;";
$connection->executeUpdate($query);
} catch (\Exception $ex) {
$this->logger->error('Database creation failed: {error}', [
diff --git a/lib/private/Share/Share.php b/lib/private/Share/Share.php
index 9210dfd1fd1..33801cd6347 100644
--- a/lib/private/Share/Share.php
+++ b/lib/private/Share/Share.php
@@ -1059,7 +1059,7 @@ class Share extends Constants {
if (isset($groupShare['file_target'])) {
$shareTmp['fileTarget'] = $groupShare['file_target'];
}
- $listOfUnsharedItems = array_merge($listOfUnsharedItems, array($groupShare));
+ $listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
$itemUnshared = true;
} elseif (!$itemUnshared && isset($uniqueGroupShare)) {
$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
@@ -1074,7 +1074,7 @@ class Share extends Constants {
if (isset($uniqueGroupShare['file_target'])) {
$shareTmp['fileTarget'] = $uniqueGroupShare['file_target'];
}
- $listOfUnsharedItems = array_merge($listOfUnsharedItems, array($uniqueGroupShare));
+ $listOfUnsharedItems = array_merge($listOfUnsharedItems, [$shareTmp]);
$itemUnshared = true;
}
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index f33c297b02d..56b9d5b1ee8 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -543,7 +543,7 @@ class DefaultShareProvider implements IShareProvider {
// If the recipient is set for a group share resolve to that user
if ($recipientId !== null && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
- $share = $this->resolveGroupShare($share, $recipientId);
+ $share = $this->resolveGroupShares([$share], $recipientId)[0];
}
return $share;
@@ -583,6 +583,25 @@ class DefaultShareProvider implements IShareProvider {
}
/**
+ * Returns whether the given database result can be interpreted as
+ * a share with accessible file (not trashed, not deleted)
+ */
+ private function isAccessibleResult($data) {
+ // exclude shares leading to deleted file entries
+ if ($data['fileid'] === null) {
+ return false;
+ }
+
+ // exclude shares leading to trashbin on home storages
+ $pathSections = explode('/', $data['path'], 2);
+ // FIXME: would not detect rare md5'd home storage case properly
+ if ($pathSections[0] !== 'files' && explode(':', $data['storage_string_id'], 2)[0] === 'home') {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* @inheritdoc
*/
public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
@@ -592,11 +611,14 @@ class DefaultShareProvider implements IShareProvider {
if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
//Get shares directly with this user
$qb = $this->dbConn->getQueryBuilder();
- $qb->select('*')
- ->from('share');
+ $qb->select('s.*', 'f.fileid', 'f.path')
+ ->selectAlias('st.id', 'storage_string_id')
+ ->from('share', 's')
+ ->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
+ ->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'));
// Order by id
- $qb->orderBy('id');
+ $qb->orderBy('s.id');
// Set limit and offset
if ($limit !== -1) {
@@ -619,7 +641,9 @@ class DefaultShareProvider implements IShareProvider {
$cursor = $qb->execute();
while($data = $cursor->fetch()) {
- $shares[] = $this->createShare($data);
+ if ($this->isAccessibleResult($data)) {
+ $shares[] = $this->createShare($data);
+ }
}
$cursor->closeCursor();
@@ -640,9 +664,12 @@ class DefaultShareProvider implements IShareProvider {
}
$qb = $this->dbConn->getQueryBuilder();
- $qb->select('*')
- ->from('share')
- ->orderBy('id')
+ $qb->select('s.*', 'f.fileid', 'f.path')
+ ->selectAlias('st.id', 'storage_string_id')
+ ->from('share', 's')
+ ->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
+ ->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
+ ->orderBy('s.id')
->setFirstResult(0);
if ($limit !== -1) {
@@ -672,18 +699,18 @@ class DefaultShareProvider implements IShareProvider {
$offset--;
continue;
}
- $shares2[] = $this->createShare($data);
+
+ if ($this->isAccessibleResult($data)) {
+ $shares2[] = $this->createShare($data);
+ }
}
$cursor->closeCursor();
}
/*
* Resolve all group shares to user specific shares
- * TODO: Optmize this!
*/
- foreach($shares2 as $share) {
- $shares[] = $this->resolveGroupShare($share, $userId);
- }
+ $shares = $this->resolveGroupShares($shares2, $userId);
} else {
throw new BackendError('Invalid backend');
}
@@ -772,37 +799,59 @@ class DefaultShareProvider implements IShareProvider {
}
/**
- * Resolve a group share to a user specific share
- * Thus if the user moved their group share make sure this is properly reflected here.
- *
- * @param \OCP\Share\IShare $share
- * @param string $userId
- * @return Share Returns the updated share if one was found else return the original share.
+ * @param Share[] $shares
+ * @param $userId
+ * @return Share[] The updates shares if no update is found for a share return the original
*/
- private function resolveGroupShare(\OCP\Share\IShare $share, $userId) {
- $qb = $this->dbConn->getQueryBuilder();
+ private function resolveGroupShares($shares, $userId) {
+ $result = [];
- $stmt = $qb->select('*')
- ->from('share')
- ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
- ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
- ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
- ->andWhere($qb->expr()->orX(
- $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
- $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
- ))
- ->setMaxResults(1)
- ->execute();
+ $start = 0;
+ while(true) {
+ /** @var Share[] $shareSlice */
+ $shareSlice = array_slice($shares, $start, 100);
+ $start += 100;
- $data = $stmt->fetch();
- $stmt->closeCursor();
+ if ($shareSlice === []) {
+ break;
+ }
+
+ /** @var int[] $ids */
+ $ids = [];
+ /** @var Share[] $shareMap */
+ $shareMap = [];
+
+ foreach ($shareSlice as $share) {
+ $ids[] = (int)$share->getId();
+ $shareMap[$share->getId()] = $share;
+ }
+
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $query = $qb->select('*')
+ ->from('share')
+ ->where($qb->expr()->in('parent', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
+ ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
+ ->andWhere($qb->expr()->orX(
+ $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
+ $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
+ ));
+
+ $stmt = $query->execute();
+
+ while($data = $stmt->fetch()) {
+ $shareMap[$data['parent']]->setPermissions((int)$data['permissions']);
+ $shareMap[$data['parent']]->setTarget($data['file_target']);
+ }
+
+ $stmt->closeCursor();
- if ($data !== false) {
- $share->setPermissions((int)$data['permissions']);
- $share->setTarget($data['file_target']);
+ foreach ($shareMap as $share) {
+ $result[] = $share;
+ }
}
- return $share;
+ return $result;
}
/**
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index b4fe69a83e2..22cf5a3f65a 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -614,8 +614,11 @@ class Manager implements IManager {
throw new \Exception($error);
}
+ $oldShare = $share;
$provider = $this->factory->getProviderForType($share->getShareType());
$share = $provider->create($share);
+ //reuse the node we already have
+ $share->setNode($oldShare->getNode());
// Post share hook
$postHookData = [
diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php
index c565809c078..e3e8482f4e1 100644
--- a/lib/private/Share20/Share.php
+++ b/lib/private/Share20/Share.php
@@ -160,7 +160,7 @@ class Share implements \OCP\Share\IShare {
$nodes = $userFolder->getById($this->fileId);
if (empty($nodes)) {
- throw new NotFoundException();
+ throw new NotFoundException('Node for share not found, fileid: ' . $this->fileId);
}
$this->node = $nodes[0];
diff --git a/lib/private/Template/JSConfigHelper.php b/lib/private/Template/JSConfigHelper.php
new file mode 100644
index 00000000000..a7f8c251cee
--- /dev/null
+++ b/lib/private/Template/JSConfigHelper.php
@@ -0,0 +1,243 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Template;
+
+use bantu\IniGetWrapper\IniGetWrapper;
+use OCP\App\IAppManager;
+use OCP\IConfig;
+use OCP\IGroupManager;
+use OCP\IL10N;
+use OCP\IURLGenerator;
+use OCP\IUser;
+
+class JSConfigHelper {
+
+ /** @var IL10N */
+ private $l;
+
+ /** @var \OC_Defaults */
+ private $defaults;
+
+ /** @var IAppManager */
+ private $appManager;
+
+ /** @var IUser */
+ private $currentUser;
+
+ /** @var IConfig */
+ private $config;
+
+ /** @var IGroupManager */
+ private $groupManager;
+
+ /** @var IniGetWrapper */
+ private $iniWrapper;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /**
+ * @param IL10N $l
+ * @param \OC_Defaults $defaults
+ * @param IAppManager $appManager
+ * @param IUser|null $currentUser
+ * @param IConfig $config
+ * @param IGroupManager $groupManager
+ * @param IniGetWrapper $iniWrapper
+ * @param IURLGenerator $urlGenerator
+ */
+ public function __construct(IL10N $l,
+ \OC_Defaults $defaults,
+ IAppManager $appManager,
+ $currentUser,
+ IConfig $config,
+ IGroupManager $groupManager,
+ IniGetWrapper $iniWrapper,
+ IURLGenerator $urlGenerator) {
+ $this->l = $l;
+ $this->defaults = $defaults;
+ $this->appManager = $appManager;
+ $this->currentUser = $currentUser;
+ $this->config = $config;
+ $this->groupManager = $groupManager;
+ $this->iniWrapper = $iniWrapper;
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ public function getConfig() {
+
+ if ($this->currentUser !== null) {
+ $uid = $this->currentUser->getUID();
+ } else {
+ $uid = null;
+ }
+
+ // Get the config
+ $apps_paths = [];
+
+ if ($this->currentUser === null) {
+ $apps = $this->appManager->getInstalledApps();
+ } else {
+ $apps = $this->appManager->getEnabledAppsForUser($this->currentUser);
+ }
+
+ foreach($apps as $app) {
+ $apps_paths[$app] = \OC_App::getAppWebPath($app);
+ }
+
+ $defaultExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
+ $defaultExpireDate = $enforceDefaultExpireDate = null;
+ if ($defaultExpireDateEnabled) {
+ $defaultExpireDate = (int) $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
+ $enforceDefaultExpireDate = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
+ }
+ $outgoingServer2serverShareEnabled = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
+
+ $countOfDataLocation = 0;
+ $dataLocation = str_replace(\OC::$SERVERROOT .'/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation);
+ if($countOfDataLocation !== 1 || !$this->groupManager->isAdmin($uid)) {
+ $dataLocation = false;
+ }
+
+ $array = [
+ "oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false',
+ "oc_isadmin" => $this->groupManager->isAdmin($uid) ? 'true' : 'false',
+ "oc_dataURL" => is_string($dataLocation) ? "\"".$dataLocation."\"" : 'false',
+ "oc_webroot" => "\"".\OC::$WEBROOT."\"",
+ "oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution
+ "datepickerFormatDate" => json_encode($this->l->l('jsdate', null)),
+ "dayNames" => json_encode([
+ (string)$this->l->t('Sunday'),
+ (string)$this->l->t('Monday'),
+ (string)$this->l->t('Tuesday'),
+ (string)$this->l->t('Wednesday'),
+ (string)$this->l->t('Thursday'),
+ (string)$this->l->t('Friday'),
+ (string)$this->l->t('Saturday')
+ ]),
+ "dayNamesShort" => json_encode([
+ (string)$this->l->t('Sun.'),
+ (string)$this->l->t('Mon.'),
+ (string)$this->l->t('Tue.'),
+ (string)$this->l->t('Wed.'),
+ (string)$this->l->t('Thu.'),
+ (string)$this->l->t('Fri.'),
+ (string)$this->l->t('Sat.')
+ ]),
+ "dayNamesMin" => json_encode([
+ (string)$this->l->t('Su'),
+ (string)$this->l->t('Mo'),
+ (string)$this->l->t('Tu'),
+ (string)$this->l->t('We'),
+ (string)$this->l->t('Th'),
+ (string)$this->l->t('Fr'),
+ (string)$this->l->t('Sa')
+ ]),
+ "monthNames" => json_encode([
+ (string)$this->l->t('January'),
+ (string)$this->l->t('February'),
+ (string)$this->l->t('March'),
+ (string)$this->l->t('April'),
+ (string)$this->l->t('May'),
+ (string)$this->l->t('June'),
+ (string)$this->l->t('July'),
+ (string)$this->l->t('August'),
+ (string)$this->l->t('September'),
+ (string)$this->l->t('October'),
+ (string)$this->l->t('November'),
+ (string)$this->l->t('December')
+ ]),
+ "monthNamesShort" => json_encode([
+ (string)$this->l->t('Jan.'),
+ (string)$this->l->t('Feb.'),
+ (string)$this->l->t('Mar.'),
+ (string)$this->l->t('Apr.'),
+ (string)$this->l->t('May.'),
+ (string)$this->l->t('Jun.'),
+ (string)$this->l->t('Jul.'),
+ (string)$this->l->t('Aug.'),
+ (string)$this->l->t('Sep.'),
+ (string)$this->l->t('Oct.'),
+ (string)$this->l->t('Nov.'),
+ (string)$this->l->t('Dec.')
+ ]),
+ "firstDay" => json_encode($this->l->l('firstday', null)) ,
+ "oc_config" => json_encode([
+ 'session_lifetime' => min($this->config->getSystemValue('session_lifetime', $this->iniWrapper->getNumeric('session.gc_maxlifetime')), $this->iniWrapper->getNumeric('session.gc_maxlifetime')),
+ 'session_keepalive' => $this->config->getSystemValue('session_keepalive', true),
+ 'version' => implode('.', \OCP\Util::getVersion()),
+ 'versionstring' => \OC_Util::getVersionString(),
+ 'enable_avatars' => $this->config->getSystemValue('enable_avatars', true) === true,
+ 'lost_password_link'=> $this->config->getSystemValue('lost_password_link', null),
+ 'modRewriteWorking' => (getenv('front_controller_active') === 'true'),
+ ]),
+ "oc_appconfig" => json_encode([
+ 'core' => [
+ 'defaultExpireDateEnabled' => $defaultExpireDateEnabled,
+ 'defaultExpireDate' => $defaultExpireDate,
+ 'defaultExpireDateEnforced' => $enforceDefaultExpireDate,
+ 'enforcePasswordForPublicLink' => \OCP\Util::isPublicLinkPasswordRequired(),
+ 'sharingDisabledForUser' => \OCP\Util::isSharingDisabledForUser(),
+ 'resharingAllowed' => \OCP\Share::isResharingAllowed(),
+ 'remoteShareAllowed' => $outgoingServer2serverShareEnabled,
+ 'federatedCloudShareDoc' => $this->urlGenerator->linkToDocs('user-sharing-federated'),
+ 'allowGroupSharing' => \OC::$server->getShareManager()->allowGroupSharing()
+ ]
+ ]),
+ "oc_defaults" => json_encode([
+ 'entity' => $this->defaults->getEntity(),
+ 'name' => $this->defaults->getName(),
+ 'title' => $this->defaults->getTitle(),
+ 'baseUrl' => $this->defaults->getBaseUrl(),
+ 'syncClientUrl' => $this->defaults->getSyncClientUrl(),
+ 'docBaseUrl' => $this->defaults->getDocBaseUrl(),
+ 'docPlaceholderUrl' => $this->defaults->buildDocLinkToKey('PLACEHOLDER'),
+ 'slogan' => $this->defaults->getSlogan(),
+ 'logoClaim' => $this->defaults->getLogoClaim(),
+ 'shortFooter' => $this->defaults->getShortFooter(),
+ 'longFooter' => $this->defaults->getLongFooter(),
+ 'folder' => \OC_Util::getTheme(),
+ ]),
+ ];
+
+ if ($this->currentUser !== null) {
+ $array['oc_userconfig'] = json_encode([
+ 'avatar' => [
+ 'version' => (int)$this->config->getUserValue($uid, 'avatar', 'version', 0),
+ ]
+ ]);
+ }
+
+ // Allow hooks to modify the output values
+ \OC_Hook::emit('\OCP\Config', 'js', array('array' => &$array));
+
+ $result = '';
+
+ // Echo it
+ foreach ($array as $setting => $value) {
+ $result .= 'var '. $setting . '='. $value . ';' . PHP_EOL;
+ }
+
+ return $result;
+ }
+}
diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php
index da845d80d04..9f89174e7f9 100644
--- a/lib/private/TemplateLayout.php
+++ b/lib/private/TemplateLayout.php
@@ -43,6 +43,7 @@ use Assetic\Filter\CssMinFilter;
use Assetic\Filter\CssRewriteFilter;
use Assetic\Filter\JSqueezeFilter;
use Assetic\Filter\SeparatorFilter;
+use OC\Template\JSConfigHelper;
class TemplateLayout extends \OC_Template {
@@ -142,7 +143,22 @@ class TemplateLayout extends \OC_Template {
$jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
$this->assign('jsfiles', array());
if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
- $this->append( 'jsfiles', \OC::$server->getURLGenerator()->linkToRoute('js_config', ['v' => self::$versionHash]));
+ if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
+ $jsConfigHelper = new JSConfigHelper(
+ \OC::$server->getL10N('core'),
+ \OC::$server->getThemingDefaults(),
+ \OC::$server->getAppManager(),
+ \OC::$server->getUserSession()->getUser(),
+ \OC::$server->getConfig(),
+ \OC::$server->getGroupManager(),
+ \OC::$server->getIniWrapper(),
+ \OC::$server->getURLGenerator()
+ );
+ $this->assign('inline_ocjs', $jsConfigHelper->getConfig());
+ $this->assign('foo', 'bar');
+ } else {
+ $this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
+ }
}
foreach($jsFiles as $info) {
$web = $info[1];
diff --git a/lib/private/Updater.php b/lib/private/Updater.php
index 609e965bfad..646fc031a83 100644
--- a/lib/private/Updater.php
+++ b/lib/private/Updater.php
@@ -35,8 +35,8 @@ use OC\Hooks\BasicEmitter;
use OC\IntegrityCheck\Checker;
use OC_App;
use OCP\IConfig;
-use OC\Setup;
use OCP\ILogger;
+use OCP\Util;
use Symfony\Component\EventDispatcher\GenericEvent;
/**
@@ -60,12 +60,6 @@ class Updater extends BasicEmitter {
private $checker;
/** @var bool */
- private $simulateStepEnabled;
-
- /** @var bool */
- private $updateStepEnabled;
-
- /** @var bool */
private $skip3rdPartyAppsDisable;
private $logLevelNames = [
@@ -87,29 +81,6 @@ class Updater extends BasicEmitter {
$this->log = $log;
$this->config = $config;
$this->checker = $checker;
- $this->simulateStepEnabled = true;
- $this->updateStepEnabled = true;
- }
-
- /**
- * Sets whether the database migration simulation must
- * be enabled.
- * This can be set to false to skip this test.
- *
- * @param bool $flag true to enable simulation, false otherwise
- */
- public function setSimulateStepEnabled($flag) {
- $this->simulateStepEnabled = $flag;
- }
-
- /**
- * Sets whether the update must be performed.
- * This can be set to false to skip the actual update.
- *
- * @param bool $flag true to enable update, false otherwise
- */
- public function setUpdateStepEnabled($flag) {
- $this->updateStepEnabled = $flag;
}
/**
@@ -131,9 +102,9 @@ class Updater extends BasicEmitter {
public function upgrade() {
$this->emitRepairEvents();
- $logLevel = $this->config->getSystemValue('loglevel', \OCP\Util::WARN);
+ $logLevel = $this->config->getSystemValue('loglevel', Util::WARN);
$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
- $this->config->setSystemValue('loglevel', \OCP\Util::DEBUG);
+ $this->config->setSystemValue('loglevel', Util::DEBUG);
$wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
@@ -254,68 +225,48 @@ class Updater extends BasicEmitter {
$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
$repair->run();
- // simulate DB upgrade
- if ($this->simulateStepEnabled) {
- $this->checkCoreUpgrade();
-
- // simulate apps DB upgrade
- $this->checkAppUpgrade($currentVersion);
+ $this->doCoreUpgrade();
+ try {
+ // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
+ Setup::installBackgroundJobs();
+ } catch (\Exception $e) {
+ throw new \Exception($e->getMessage());
}
- if ($this->updateStepEnabled) {
- $this->doCoreUpgrade();
-
- try {
- // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
- Setup::installBackgroundJobs();
- } catch (\Exception $e) {
- throw new \Exception($e->getMessage());
- }
-
- // update all shipped apps
- $disabledApps = $this->checkAppsRequirements();
- $this->doAppUpgrade();
+ // update all shipped apps
+ $disabledApps = $this->checkAppsRequirements();
+ $this->doAppUpgrade();
- // upgrade appstore apps
- $this->upgradeAppStoreApps($disabledApps);
-
- // install new shipped apps on upgrade
- OC_App::loadApps('authentication');
- $errors = Installer::installShippedApps(true);
- foreach ($errors as $appId => $exception) {
- /** @var \Exception $exception */
- $this->log->logException($exception, ['app' => $appId]);
- $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
- }
+ // upgrade appstore apps
+ $this->upgradeAppStoreApps($disabledApps);
- // post-upgrade repairs
- $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
- $repair->run();
+ // install new shipped apps on upgrade
+ OC_App::loadApps('authentication');
+ $errors = Installer::installShippedApps(true);
+ foreach ($errors as $appId => $exception) {
+ /** @var \Exception $exception */
+ $this->log->logException($exception, ['app' => $appId]);
+ $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
+ }
- //Invalidate update feed
- $this->config->setAppValue('core', 'lastupdatedat', 0);
+ // post-upgrade repairs
+ $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
+ $repair->run();
- // Check for code integrity if not disabled
- if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
- $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
- $this->checker->runInstanceVerification();
- $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
- }
+ //Invalidate update feed
+ $this->config->setAppValue('core', 'lastupdatedat', 0);
- // only set the final version if everything went well
- $this->config->setSystemValue('version', implode('.', \OCP\Util::getVersion()));
- $this->config->setAppValue('core', 'vendor', $this->getVendor());
+ // Check for code integrity if not disabled
+ if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
+ $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
+ $this->checker->runInstanceVerification();
+ $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
}
- }
- protected function checkCoreUpgrade() {
- $this->emit('\OC\Updater', 'dbSimulateUpgradeBefore');
-
- // simulate core DB upgrade
- \OC_DB::simulateUpdateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml');
-
- $this->emit('\OC\Updater', 'dbSimulateUpgrade');
+ // only set the final version if everything went well
+ $this->config->setSystemValue('version', implode('.', Util::getVersion()));
+ $this->config->setAppValue('core', 'vendor', $this->getVendor());
}
protected function doCoreUpgrade() {
@@ -424,7 +375,7 @@ class Updater extends BasicEmitter {
private function checkAppsRequirements() {
$isCoreUpgrade = $this->isCodeUpgrade();
$apps = OC_App::getEnabledApps();
- $version = \OCP\Util::getVersion();
+ $version = Util::getVersion();
$disabledApps = [];
foreach ($apps as $app) {
// check if the app is compatible with this version of ownCloud
@@ -461,7 +412,7 @@ class Updater extends BasicEmitter {
*/
private function isCodeUpgrade() {
$installedVersion = $this->config->getSystemValue('version', '0.0.0');
- $currentVersion = implode('.', \OCP\Util::getVersion());
+ $currentVersion = implode('.', Util::getVersion());
if (version_compare($currentVersion, $installedVersion, '>')) {
return true;
}
diff --git a/lib/private/Updater/VersionCheck.php b/lib/private/Updater/VersionCheck.php
index e846052a300..f66e109fd26 100644
--- a/lib/private/Updater/VersionCheck.php
+++ b/lib/private/Updater/VersionCheck.php
@@ -59,7 +59,7 @@ class VersionCheck {
return json_decode($this->config->getAppValue('core', 'lastupdateResult'), true);
}
- $updaterUrl = $this->config->getSystemValue('updater.server.url', 'https://updates.nextcloud.com/update-server/');
+ $updaterUrl = $this->config->getSystemValue('updater.server.url', 'https://updates.nextcloud.com/updater_server/');
$this->config->setAppValue('core', 'lastupdatedat', time());
@@ -89,6 +89,7 @@ class VersionCheck {
$tmp['versionstring'] = (string)$data->versionstring;
$tmp['url'] = (string)$data->url;
$tmp['web'] = (string)$data->web;
+ $tmp['autoupdater'] = (string)$data->autoupdater;
} else {
libxml_clear_errors();
}
diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php
index eba7beffeae..28cb3302858 100644
--- a/lib/private/User/Database.php
+++ b/lib/private/User/Database.php
@@ -94,6 +94,9 @@ class Database extends Backend implements IUserBackend {
$query = \OC_DB::prepare('INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )');
$result = $query->execute(array($uid, \OC::$server->getHasher()->hash($password)));
+ // Clear cache
+ unset($this->cache[$uid]);
+
return $result ? true : false;
}
@@ -234,7 +237,7 @@ class Database extends Backend implements IUserBackend {
* @return boolean
*/
private function loadUser($uid) {
- if (empty($this->cache[$uid])) {
+ if (!isset($this->cache[$uid])) {
$query = \OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)');
$result = $query->execute(array($uid));
@@ -243,6 +246,8 @@ class Database extends Backend implements IUserBackend {
return false;
}
+ $this->cache[$uid] = false;
+
while ($row = $result->fetchRow()) {
$this->cache[$uid]['uid'] = $row['uid'];
$this->cache[$uid]['displayname'] = $row['displayname'];
@@ -284,7 +289,7 @@ class Database extends Backend implements IUserBackend {
*/
public function userExists($uid) {
$this->loadUser($uid);
- return !empty($this->cache[$uid]);
+ return $this->cache[$uid] !== false;
}
/**
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index dec959820f8..a213ee48c2a 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -362,6 +362,9 @@ class Session implements IUserSession, Emitter {
$user = $this->manager->get($username);
if (is_null($user)) {
$users = $this->manager->getByEmail($username);
+ if (empty($users)) {
+ return false;
+ }
if (count($users) !== 1) {
return true;
}
@@ -597,7 +600,6 @@ class Session implements IUserSession, Emitter {
}
$dbToken->setLastCheck($now);
- $this->tokenProvider->updateToken($dbToken);
return true;
}
@@ -608,7 +610,6 @@ class Session implements IUserSession, Emitter {
return false;
}
$dbToken->setLastCheck($now);
- $this->tokenProvider->updateToken($dbToken);
return true;
}
diff --git a/lib/private/User/User.php b/lib/private/User/User.php
index 94ac8c13621..68787ce60f8 100644
--- a/lib/private/User/User.php
+++ b/lib/private/User/User.php
@@ -214,10 +214,14 @@ class User implements IUser {
\OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
- }
- if ($this->emitter) {
- $this->emitter->emit('\OC\User', 'postDelete', array($this));
+ $notification = \OC::$server->getNotificationManager()->createNotification();
+ $notification->setUser($this->uid);
+ \OC::$server->getNotificationManager()->markProcessed($notification);
+
+ if ($this->emitter) {
+ $this->emitter->emit('\OC\User', 'postDelete', array($this));
+ }
}
return !($result === false);
}
diff --git a/lib/private/legacy/app.php b/lib/private/legacy/app.php
index d964212f3bb..d25534aa822 100644
--- a/lib/private/legacy/app.php
+++ b/lib/private/legacy/app.php
@@ -47,6 +47,7 @@
*
*/
use OC\App\DependencyAnalyzer;
+use OC\App\InfoParser;
use OC\App\Platform;
use OC\Installer;
use OC\OCSClient;
@@ -333,9 +334,16 @@ class OC_App {
* This function set an app as enabled in appconfig.
*/
public static function enable($app, $groups = null) {
- self::$enabledAppsCache = array(); // flush
+ self::$enabledAppsCache = []; // flush
if (!Installer::isInstalled($app)) {
$app = self::installApp($app);
+ } else {
+ // check for required dependencies
+ $config = \OC::$server->getConfig();
+ $l = \OC::$server->getL10N('core');
+ $info = self::getAppInfo($app);
+
+ self::checkAppDependencies($config, $l, $info);
}
$appManager = \OC::$server->getAppManager();
@@ -662,15 +670,16 @@ class OC_App {
* Read all app metadata from the info.xml file
*
* @param string $appId id of the app or the path of the info.xml file
- * @param boolean $path (optional)
+ * @param bool $path
+ * @param string $lang
* @return array|null
* @note all data is read from info.xml, not just pre-defined fields
*/
- public static function getAppInfo($appId, $path = false) {
+ public static function getAppInfo($appId, $path = false, $lang = null) {
if ($path) {
$file = $appId;
} else {
- if (isset(self::$appInfo[$appId])) {
+ if ($lang === null && isset(self::$appInfo[$appId])) {
return self::$appInfo[$appId];
}
$appPath = self::getAppPath($appId);
@@ -680,11 +689,11 @@ class OC_App {
$file = $appPath . '/appinfo/info.xml';
}
- $parser = new \OC\App\InfoParser(\OC::$server->getURLGenerator());
+ $parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
$data = $parser->parse($file);
if (is_array($data)) {
- $data = OC_App::parseAppInfo($data);
+ $data = OC_App::parseAppInfo($data, $lang);
}
if(isset($data['ocsid'])) {
$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
@@ -693,7 +702,9 @@ class OC_App {
}
}
- self::$appInfo[$appId] = $data;
+ if ($lang === null) {
+ self::$appInfo[$appId] = $data;
+ }
return $data;
}
@@ -843,11 +854,13 @@ class OC_App {
//we don't want to show configuration for these
$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
$appList = array();
+ $langCode = \OC::$server->getL10N('core')->getLanguageCode();
+ $urlGenerator = \OC::$server->getURLGenerator();
foreach ($installedApps as $app) {
if (array_search($app, $blacklist) === false) {
- $info = OC_App::getAppInfo($app);
+ $info = OC_App::getAppInfo($app, false, $langCode);
if (!is_array($info)) {
\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
continue;
@@ -896,6 +909,19 @@ class OC_App {
}
}
}
+ // fix documentation
+ if (isset($info['documentation']) && is_array($info['documentation'])) {
+ foreach ($info['documentation'] as $key => $url) {
+ // If it is not an absolute URL we assume it is a key
+ // i.e. admin-ldap will get converted to go.php?to=admin-ldap
+ if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
+ $url = $urlGenerator->linkToDocs($url);
+ }
+
+ $info['documentation'][$key] = $url;
+ }
+ }
+
$info['version'] = OC_App::getAppVersion($app);
$appList[] = $info;
}
@@ -1167,16 +1193,7 @@ class OC_App {
}
// check for required dependencies
- $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
- $missing = $dependencyAnalyzer->analyze($info);
- if (!empty($missing)) {
- $missingMsg = join(PHP_EOL, $missing);
- throw new \Exception(
- $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
- array($info['name'], $missingMsg)
- )
- );
- }
+ self::checkAppDependencies($config, $l, $info);
$config->setAppValue($app, 'enabled', 'yes');
if (isset($appData['id'])) {
@@ -1327,13 +1344,69 @@ class OC_App {
}
}
+ protected static function findBestL10NOption($options, $lang) {
+ $fallback = $similarLangFallback = $englishFallback = false;
+
+ $lang = strtolower($lang);
+ $similarLang = $lang;
+ if (strpos($similarLang, '_')) {
+ // For "de_DE" we want to find "de" and the other way around
+ $similarLang = substr($lang, 0, strpos($lang, '_'));
+ }
+
+ foreach ($options as $option) {
+ if (is_array($option)) {
+ if ($fallback === false) {
+ $fallback = $option['@value'];
+ }
+
+ if (!isset($option['@attributes']['lang'])) {
+ continue;
+ }
+
+ $attributeLang = strtolower($option['@attributes']['lang']);
+ if ($attributeLang === $lang) {
+ return $option['@value'];
+ }
+
+ if ($attributeLang === $similarLang) {
+ $similarLangFallback = $option['@value'];
+ } else if (strpos($attributeLang, $similarLang . '_') === 0) {
+ if ($similarLangFallback === false) {
+ $similarLangFallback = $option['@value'];
+ }
+ }
+ } else {
+ $englishFallback = $option;
+ }
+ }
+
+ if ($similarLangFallback !== false) {
+ return $similarLangFallback;
+ } else if ($englishFallback !== false) {
+ return $englishFallback;
+ }
+ return (string) $fallback;
+ }
+
/**
* parses the app data array and enhanced the 'description' value
*
* @param array $data the app data
+ * @param string $lang
* @return array improved app data
*/
- public static function parseAppInfo(array $data) {
+ public static function parseAppInfo(array $data, $lang = null) {
+
+ if ($lang && isset($data['name']) && is_array($data['name'])) {
+ $data['name'] = self::findBestL10NOption($data['name'], $lang);
+ }
+ if ($lang && isset($data['summary']) && is_array($data['summary'])) {
+ $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
+ }
+ if ($lang && isset($data['description']) && is_array($data['description'])) {
+ $data['description'] = self::findBestL10NOption($data['description'], $lang);
+ }
// just modify the description if it is available
// otherwise this will create a $data element with an empty 'description'
@@ -1363,4 +1436,23 @@ class OC_App {
return $data;
}
+
+ /**
+ * @param $config
+ * @param $l
+ * @param $info
+ * @throws Exception
+ */
+ protected static function checkAppDependencies($config, $l, $info) {
+ $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
+ $missing = $dependencyAnalyzer->analyze($info);
+ if (!empty($missing)) {
+ $missingMsg = join(PHP_EOL, $missing);
+ throw new \Exception(
+ $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
+ [$info['name'], $missingMsg]
+ )
+ );
+ }
+ }
}
diff --git a/lib/private/legacy/db.php b/lib/private/legacy/db.php
index 2d48e830ec2..415701d4024 100644
--- a/lib/private/legacy/db.php
+++ b/lib/private/legacy/db.php
@@ -192,23 +192,6 @@ class OC_DB {
}
/**
- * simulate the database schema update
- * @param string $file file to read structure from
- * @throws Exception
- * @return string|boolean
- */
- public static function simulateUpdateDbFromStructure($file) {
- $schemaManager = self::getMDB2SchemaManager();
- try {
- $result = $schemaManager->simulateUpdateDbFromStructure($file);
- } catch (Exception $e) {
- \OCP\Util::writeLog('core', 'Simulated database structure update failed ('.$e.')', \OCP\Util::FATAL);
- throw $e;
- }
- return $result;
- }
-
- /**
* remove all tables defined in a database structure xml file
* @param string $file the xml file describing the tables
*/
diff --git a/lib/private/legacy/helper.php b/lib/private/legacy/helper.php
index b19e58a9e6c..9c4bc895fb9 100644
--- a/lib/private/legacy/helper.php
+++ b/lib/private/legacy/helper.php
@@ -254,16 +254,9 @@ class OC_Helper {
if ($path === false) {
$path = getenv("PATH");
}
- // check method depends on operating system
- if (!strncmp(PHP_OS, "WIN", 3)) {
- // on Windows an appropriate COM or EXE file needs to exist
- $exts = array(".exe", ".com");
- $check_fn = "file_exists";
- } else {
- // anywhere else we look for an executable file of that name
- $exts = array("");
- $check_fn = "is_executable";
- }
+ // we look for an executable file of that name
+ $exts = [""];
+ $check_fn = "is_executable";
// Default check will be done with $path directories :
$dirs = explode(PATH_SEPARATOR, $path);
// WARNING : We have to check if open_basedir is enabled :
@@ -378,32 +371,6 @@ class OC_Helper {
}
/**
- * Checks if $sub is a subdirectory of $parent
- *
- * @param string $sub
- * @param string $parent
- * @return bool
- */
- public static function isSubDirectory($sub, $parent) {
- $realpathSub = realpath($sub);
- $realpathParent = realpath($parent);
-
- // realpath() may return false in case the directory does not exist
- // since we can not be sure how different PHP versions may behave here
- // we do an additional check whether realpath returned false
- if($realpathSub === false || $realpathParent === false) {
- return false;
- }
-
- // Check whether $sub is a subdirectory of $parent
- if (strpos($realpathSub, $realpathParent) === 0) {
- return true;
- }
-
- return false;
- }
-
- /**
* Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
*
* @param array $input The array to work on
@@ -524,7 +491,6 @@ class OC_Helper {
/**
* Try to find a program
- * Note: currently windows is not supported
*
* @param string $program
* @return null|string
@@ -583,7 +549,7 @@ class OC_Helper {
$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
$storage = $rootInfo->getStorage();
$sourceStorage = $storage;
- if ($storage->instanceOfStorage('\OC\Files\Storage\Shared')) {
+ if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
$includeExtStorage = false;
$sourceStorage = $storage->getSourceStorage();
}
diff --git a/lib/private/legacy/ocs.php b/lib/private/legacy/ocs.php
index 2ed17e7dae0..a03cba7bc1a 100644
--- a/lib/private/legacy/ocs.php
+++ b/lib/private/legacy/ocs.php
@@ -37,7 +37,7 @@ class OC_OCS {
$format = \OC::$server->getRequest()->getParam('format', 'xml');
$txt='Invalid query, please check the syntax. API specifications are here:'
.' http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
- OC_API::respond(new OC_OCS_Result(null, API::RESPOND_UNKNOWN_ERROR, $txt), $format);
+ OC_API::respond(new OC_OCS_Result(null, API::RESPOND_NOT_FOUND, $txt), $format);
}
}
diff --git a/lib/private/legacy/response.php b/lib/private/legacy/response.php
index 0ec27251ba5..88725d5e30b 100644
--- a/lib/private/legacy/response.php
+++ b/lib/private/legacy/response.php
@@ -33,6 +33,7 @@ class OC_Response {
const STATUS_NOT_MODIFIED = 304;
const STATUS_TEMPORARY_REDIRECT = 307;
const STATUS_BAD_REQUEST = 400;
+ const STATUS_FORBIDDEN = 403;
const STATUS_NOT_FOUND = 404;
const STATUS_INTERNAL_SERVER_ERROR = 500;
const STATUS_SERVICE_UNAVAILABLE = 503;
diff --git a/lib/private/legacy/template.php b/lib/private/legacy/template.php
index 477fd624a9d..7c0b58db0c0 100644
--- a/lib/private/legacy/template.php
+++ b/lib/private/legacy/template.php
@@ -117,7 +117,7 @@ class OC_Template extends \OC\Template\Base {
OC_Util::addStyle("fonts",null,true);
OC_Util::addStyle("icons",null,true);
OC_Util::addStyle("header",null,true);
- OC_Util::addStyle("inputs",null,true);
+ OC_Util::addStyle("inputs");
OC_Util::addStyle("styles",null,true);
// avatars
@@ -126,6 +126,10 @@ class OC_Template extends \OC\Template\Base {
\OC_Util::addScript('placeholder', null, true);
}
+ OC_Util::addVendorScript('select2/select2');
+ OC_Util::addVendorStyle('select2/select2', null, true);
+ OC_Util::addScript('select2-toggleselect');
+
OC_Util::addScript('oc-backbone', null, true);
OC_Util::addVendorScript('core', 'backbone/backbone', true);
OC_Util::addVendorScript('snapjs/dist/latest/snap', null, true);
@@ -135,6 +139,7 @@ class OC_Template extends \OC\Template\Base {
OC_Util::addScript("oc-requesttoken", null, true);
OC_Util::addScript('search', 'search', true);
OC_Util::addScript("config", null, true);
+ OC_Util::addScript("public/appconfig", null, true);
OC_Util::addScript("eventsource", null, true);
OC_Util::addScript("octemplate", null, true);
OC_Util::addTranslations("core", null, true);
@@ -143,8 +148,6 @@ class OC_Template extends \OC\Template\Base {
OC_Util::addScript("oc-dialogs", null, true);
OC_Util::addScript("jquery.ocdialog", null, true);
OC_Util::addStyle("jquery.ocdialog");
- OC_Util::addScript("compatibility", null, true);
- OC_Util::addScript("placeholders", null, true);
OC_Util::addScript('files/fileinfo');
OC_Util::addScript('files/client');
diff --git a/lib/private/legacy/util.php b/lib/private/legacy/util.php
index 04dcb8fc896..42fd0ba7db3 100644
--- a/lib/private/legacy/util.php
+++ b/lib/private/legacy/util.php
@@ -165,15 +165,14 @@ class OC_Util {
// install storage availability wrapper, before most other wrappers
\OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, $storage) {
- /** @var \OCP\Files\Storage $storage */
- if (!$storage->instanceOfStorage('\OC\Files\Storage\Shared') && !$storage->isLocal()) {
+ if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
}
return $storage;
});
\OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
- if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OC\Files\Storage\Shared') && !$storage->isLocal()) {
+ if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
}
return $storage;
@@ -311,10 +310,20 @@ class OC_Util {
*
* @param String $userId
* @param \OCP\Files\Folder $userDirectory
+ * @throws \RuntimeException
*/
public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
- $skeletonDirectory = \OCP\Config::getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
+ $skeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
+ $instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
+
+ if ($instanceId === null) {
+ throw new \RuntimeException('no instance id!');
+ }
+ $appdata = 'appdata_' . $instanceId;
+ if ($userId === $appdata) {
+ throw new \RuntimeException('username is reserved name: ' . $appdata);
+ }
if (!empty($skeletonDirectory)) {
\OCP\Util::writeLog(
@@ -336,7 +345,16 @@ class OC_Util {
* @return void
*/
public static function copyr($source, \OCP\Files\Folder $target) {
+ $logger = \OC::$server->getLogger();
+
+ // Verify if folder exists
$dir = opendir($source);
+ if($dir === false) {
+ $logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
+ return;
+ }
+
+ // Copy the files
while (false !== ($file = readdir($dir))) {
if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
if (is_dir($source . '/' . $file)) {
@@ -344,7 +362,13 @@ class OC_Util {
self::copyr($source . '/' . $file, $child);
} else {
$child = $target->newFile($file);
- stream_copy_to_stream(fopen($source . '/' . $file,'r'), $child->fopen('w'));
+ $sourceStream = fopen($source . '/' . $file, 'r');
+ if($sourceStream === false) {
+ $logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
+ closedir($dir);
+ return;
+ }
+ stream_copy_to_stream($sourceStream, $child->fopen('w'));
}
}
}
@@ -643,15 +667,6 @@ class OC_Util {
$webServerRestart = true;
}
- // Check if server running on Windows platform
- if(OC_Util::runningOnWindows()) {
- $errors[] = [
- 'error' => $l->t('Microsoft Windows Platform is not supported'),
- 'hint' => $l->t('Running Nextcloud Server on the Microsoft Windows platform is not supported. We suggest you ' .
- 'use a Linux server in a virtual machine if you have no option for migrating the server itself.')
- ];
- }
-
// Check if config folder is writable.
if(!OC_Helper::isReadOnlyConfigEnabled()) {
if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
@@ -1244,15 +1259,6 @@ class OC_Util {
}
/**
- * Checks whether the server is running on Windows
- *
- * @return bool true if running on Windows, false otherwise
- */
- public static function runningOnWindows() {
- return (substr(PHP_OS, 0, 3) === "WIN");
- }
-
- /**
* Checks whether the server is running on Mac OS X
*
* @return bool true if running on Mac OS X, false otherwise