summaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/app.php49
-rw-r--r--lib/private/app/codechecker/infochecker.php5
-rw-r--r--lib/private/app/infoparser.php1
-rw-r--r--lib/private/app/platform.php2
-rw-r--r--lib/private/appframework/dependencyinjection/dicontainer.php8
-rw-r--r--lib/private/appframework/http/request.php2
-rw-r--r--lib/private/appframework/middleware/security/securitymiddleware.php1
-rw-r--r--lib/private/appframework/utility/controllermethodreflector.php22
-rw-r--r--lib/private/archive/tar.php2
-rw-r--r--lib/private/avatar.php81
-rw-r--r--lib/private/backgroundjob/job.php1
-rw-r--r--lib/private/backgroundjob/joblist.php176
-rw-r--r--lib/private/db.php69
-rw-r--r--lib/private/defaults.php2
-rw-r--r--lib/private/eventsource.php2
-rw-r--r--lib/private/files/cache/scanner.php6
-rw-r--r--lib/private/files/cache/storage.php4
-rw-r--r--lib/private/files/objectstore/objectstorestorage.php4
-rw-r--r--lib/private/files/storage/common.php4
-rw-r--r--lib/private/files/storage/dav.php22
-rw-r--r--lib/private/files/storage/localtempfiletrait.php2
-rw-r--r--lib/private/files/storage/temporary.php2
-rw-r--r--lib/private/files/type/detection.php2
-rw-r--r--lib/private/files/view.php12
-rw-r--r--lib/private/helper.php178
-rw-r--r--lib/private/image.php14
-rw-r--r--lib/private/installer.php12
-rw-r--r--lib/private/json.php2
-rw-r--r--lib/private/legacy/config.php94
-rw-r--r--lib/private/log.php2
-rw-r--r--lib/private/log/owncloud.php5
-rw-r--r--lib/private/memcache/apcu.php101
-rw-r--r--lib/private/ocs/cloud.php2
-rw-r--r--lib/private/ocsclient.php1
-rw-r--r--lib/private/preview.php2
-rw-r--r--lib/private/preview/movie.php4
-rw-r--r--lib/private/repair.php5
-rw-r--r--lib/private/repair/assetcache.php45
-rw-r--r--lib/private/repair/cleantags.php146
-rw-r--r--lib/private/repair/collation.php90
-rw-r--r--lib/private/repair/dropoldjobs.php78
-rw-r--r--lib/private/repair/dropoldtables.php96
-rw-r--r--lib/private/repair/filletags.php55
-rw-r--r--lib/private/repair/innodb.php69
-rw-r--r--lib/private/repair/oldgroupmembershipshares.php117
-rw-r--r--lib/private/repair/preview.php45
-rw-r--r--lib/private/repair/removegetetagentries.php59
-rw-r--r--lib/private/repair/repairinvalidshares.php112
-rw-r--r--lib/private/repair/repairlegacystorages.php263
-rw-r--r--lib/private/repair/repairmimetypes.php360
-rw-r--r--lib/private/repair/searchlucenetables.php77
-rw-r--r--lib/private/repair/sqliteautoincrement.php98
-rw-r--r--lib/private/repair/updatecertificatestore.php88
-rw-r--r--lib/private/repair/updateoutdatedocsids.php108
-rw-r--r--lib/private/route/router.php111
-rw-r--r--lib/private/security/crypto.php2
-rw-r--r--lib/private/security/hasher.php2
-rw-r--r--lib/private/security/securerandom.php45
-rw-r--r--lib/private/security/stringutils.php60
-rw-r--r--lib/private/server.php13
-rw-r--r--lib/private/servercontainer.php89
-rw-r--r--lib/private/session/cryptosessiondata.php10
-rw-r--r--lib/private/session/internal.php30
-rw-r--r--lib/private/session/memory.php7
-rw-r--r--lib/private/setup.php38
-rw-r--r--lib/private/share/helper.php34
-rw-r--r--lib/private/share/mailnotifications.php6
-rw-r--r--lib/private/share/share.php23
-rw-r--r--lib/private/share20/defaultshareprovider.php124
-rw-r--r--lib/private/share20/ishare.php35
-rw-r--r--lib/private/share20/ishareprovider.php3
-rw-r--r--lib/private/share20/manager.php540
-rw-r--r--lib/private/share20/share.php2
-rw-r--r--lib/private/systemconfig.php17
-rw-r--r--lib/private/tags.php2
-rw-r--r--lib/private/template.php3
-rw-r--r--lib/private/template/functions.php6
-rw-r--r--lib/private/templatelayout.php18
-rw-r--r--lib/private/updater.php14
-rw-r--r--lib/private/user.php125
-rw-r--r--lib/private/user/database.php4
-rw-r--r--lib/private/user/session.php2
-rw-r--r--lib/private/util.php68
83 files changed, 3337 insertions, 905 deletions
diff --git a/lib/private/app.php b/lib/private/app.php
index abf12264c58..500a60060e6 100644
--- a/lib/private/app.php
+++ b/lib/private/app.php
@@ -96,7 +96,7 @@ class OC_App {
* if $types is set, only apps of those types will be loaded
*/
public static function loadApps($types = null) {
- if (OC_Config::getValue('maintenance', false)) {
+ if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
return false;
}
// Load the enabled apps here
@@ -239,7 +239,7 @@ class OC_App {
* @return string[]
*/
public static function getEnabledApps($forceRefresh = false, $all = false) {
- if (!OC_Config::getValue('installed', false)) {
+ if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
return array();
}
// in incognito mode or when logged out, $user will be false,
@@ -318,8 +318,8 @@ class OC_App {
\OC::$server->getConfig(),
\OC::$server->getLogger()
);
- $appData = $ocsClient->getApplication($app, \OC_Util::getVersion());
- $download= $ocsClient->getApplicationDownload($app, \OC_Util::getVersion());
+ $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
+ $download= $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
if(isset($download['downloadlink']) and $download['downloadlink']!='') {
// Replace spaces in download link without encoding entire URL
$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
@@ -374,13 +374,13 @@ class OC_App {
$settings = array();
// by default, settings only contain the help menu
if (OC_Util::getEditionString() === '' &&
- OC_Config::getValue('knowledgebaseenabled', true) == true
+ \OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true) == true
) {
$settings = array(
array(
"id" => "help",
"order" => 1000,
- "href" => OC_Helper::linkToRoute("settings_help"),
+ "href" => \OC::$server->getURLGenerator()->linkToRoute('settings_help'),
"name" => $l->t("Help"),
"icon" => OC_Helper::imagePath("settings", "help.svg")
)
@@ -393,7 +393,7 @@ class OC_App {
$settings[] = array(
"id" => "personal",
"order" => 1,
- "href" => OC_Helper::linkToRoute("settings_personal"),
+ "href" => \OC::$server->getURLGenerator()->linkToRoute('settings_personal'),
"name" => $l->t("Personal"),
"icon" => OC_Helper::imagePath("settings", "personal.svg")
);
@@ -409,7 +409,7 @@ class OC_App {
$settings[] = array(
"id" => "core_users",
"order" => 2,
- "href" => OC_Helper::linkToRoute("settings_users"),
+ "href" => \OC::$server->getURLGenerator()->linkToRoute('settings_users'),
"name" => $l->t("Users"),
"icon" => OC_Helper::imagePath("settings", "users.svg")
);
@@ -421,7 +421,7 @@ class OC_App {
$settings[] = array(
"id" => "admin",
"order" => 1000,
- "href" => OC_Helper::linkToRoute("settings_admin"),
+ "href" => \OC::$server->getURLGenerator()->linkToRoute('settings_admin'),
"name" => $l->t("Admin"),
"icon" => OC_Helper::imagePath("settings", "admin.svg")
);
@@ -455,7 +455,7 @@ class OC_App {
* @return string|false
*/
public static function getInstallPath() {
- if (OC_Config::getValue('appstoreenabled', true) == false) {
+ if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
return false;
}
@@ -760,9 +760,12 @@ class OC_App {
* @param bool $onlyLocal
* @param bool $includeUpdateInfo Should we check whether there is an update
* in the app store?
+ * @param OCSClient $ocsClient
* @return array
*/
- public static function listAllApps($onlyLocal = false, $includeUpdateInfo = true) {
+ public static function listAllApps($onlyLocal = false,
+ $includeUpdateInfo = true,
+ OCSClient $ocsClient) {
$installedApps = OC_App::getAllApps();
//TODO which apps do we want to blacklist and how do we integrate
@@ -825,7 +828,7 @@ class OC_App {
if ($onlyLocal) {
$remoteApps = [];
} else {
- $remoteApps = OC_App::getAppstoreApps();
+ $remoteApps = OC_App::getAppstoreApps('approved', null, $ocsClient);
}
if ($remoteApps) {
// Remove duplicates
@@ -865,22 +868,18 @@ class OC_App {
/**
* Get a list of all apps on the appstore
* @param string $filter
- * @param string $category
+ * @param string|null $category
+ * @param OCSClient $ocsClient
* @return array|bool multi-dimensional array of apps.
* Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
*/
- public static function getAppstoreApps($filter = 'approved', $category = null) {
+ public static function getAppstoreApps($filter = 'approved',
+ $category = null,
+ OCSClient $ocsClient) {
$categories = [$category];
- $ocsClient = new OCSClient(
- \OC::$server->getHTTPClientService(),
- \OC::$server->getConfig(),
- \OC::$server->getLogger()
- );
-
-
if (is_null($category)) {
- $categoryNames = $ocsClient->getCategories(\OC_Util::getVersion());
+ $categoryNames = $ocsClient->getCategories(\OCP\Util::getVersion());
if (is_array($categoryNames)) {
// Check that categories of apps were retrieved correctly
if (!$categories = array_keys($categoryNames)) {
@@ -892,7 +891,7 @@ class OC_App {
}
$page = 0;
- $remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OC_Util::getVersion());
+ $remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OCP\Util::getVersion());
$apps = [];
$i = 0;
$l = \OC::$server->getL10N('core');
@@ -1050,7 +1049,7 @@ class OC_App {
$config,
\OC::$server->getLogger()
);
- $appData = $ocsClient->getApplication($app, \OC_Util::getVersion());
+ $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
// check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
if (!is_numeric($app)) {
@@ -1080,7 +1079,7 @@ class OC_App {
if ($app !== false) {
// check if the app is compatible with this version of ownCloud
$info = self::getAppInfo($app);
- $version = OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
if (!self::isAppCompatible($version, $info)) {
throw new \Exception(
$l->t('App "%s" cannot be installed because it is not compatible with this version of ownCloud.',
diff --git a/lib/private/app/codechecker/infochecker.php b/lib/private/app/codechecker/infochecker.php
index 24835d8148f..2589277118b 100644
--- a/lib/private/app/codechecker/infochecker.php
+++ b/lib/private/app/codechecker/infochecker.php
@@ -83,13 +83,18 @@ class InfoChecker extends BasicEmitter {
'type' => 'duplicateRequirement',
'field' => 'min',
];
+ } else if (!isset($info['dependencies']['owncloud']['@attributes']['min-version'])) {
+ $this->emit('InfoChecker', 'missingRequirement', ['min']);
}
+
if (isset($info['dependencies']['owncloud']['@attributes']['max-version']) && $info['requiremax']) {
$this->emit('InfoChecker', 'duplicateRequirement', ['max']);
$errors[] = [
'type' => 'duplicateRequirement',
'field' => 'max',
];
+ } else if (!isset($info['dependencies']['owncloud']['@attributes']['max-version'])) {
+ $this->emit('InfoChecker', 'missingRequirement', ['max']);
}
foreach ($info as $key => $value) {
diff --git a/lib/private/app/infoparser.php b/lib/private/app/infoparser.php
index 22f705884bc..a84163612e8 100644
--- a/lib/private/app/infoparser.php
+++ b/lib/private/app/infoparser.php
@@ -59,6 +59,7 @@ class InfoParser {
$xml = simplexml_load_file($file);
libxml_disable_entity_loader($loadEntities);
if ($xml == false) {
+ libxml_clear_errors();
return null;
}
$array = $this->xmlToArray($xml);
diff --git a/lib/private/app/platform.php b/lib/private/app/platform.php
index f433ecd9f9e..c16f050e13c 100644
--- a/lib/private/app/platform.php
+++ b/lib/private/app/platform.php
@@ -52,7 +52,7 @@ class Platform {
* @return string
*/
public function getOcVersion() {
- $v = OC_Util::getVersion();
+ $v = \OCP\Util::getVersion();
return join('.', $v);
}
diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php
index ce6523cc8a8..69476d84c9b 100644
--- a/lib/private/appframework/dependencyinjection/dicontainer.php
+++ b/lib/private/appframework/dependencyinjection/dicontainer.php
@@ -62,6 +62,10 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$this['AppName'] = $appName;
$this['urlParams'] = $urlParams;
+ /** @var \OC\ServerContainer $server */
+ $server = $this->getServer();
+ $server->registerAppContainer($appName, $this);
+
// aliases
$this->registerAlias('appName', 'AppName');
$this->registerAlias('webRoot', 'WebRoot');
@@ -161,6 +165,10 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$this->registerAlias('OCP\\AppFramework\\Utility\\IControllerMethodReflector', 'OC\AppFramework\Utility\ControllerMethodReflector');
$this->registerAlias('ControllerMethodReflector', 'OCP\\AppFramework\\Utility\\IControllerMethodReflector');
+ $this->registerService('OCP\\Files\\IMimeTypeDetector', function($c) {
+ return $this->getServer()->getMimeTypeDetector();
+ });
+
$this->registerService('OCP\\INavigationManager', function($c) {
return $this->getServer()->getNavigationManager();
});
diff --git a/lib/private/appframework/http/request.php b/lib/private/appframework/http/request.php
index 2bbb70db0f8..6ba1d8f644d 100644
--- a/lib/private/appframework/http/request.php
+++ b/lib/private/appframework/http/request.php
@@ -447,7 +447,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
$deobfuscatedToken = base64_decode($obfuscatedToken) ^ $secret;
// Check if the token is valid
- if(\OCP\Security\StringUtils::equals($deobfuscatedToken, $this->items['requesttoken'])) {
+ if(hash_equals($deobfuscatedToken, $this->items['requesttoken'])) {
return true;
} else {
return false;
diff --git a/lib/private/appframework/middleware/security/securitymiddleware.php b/lib/private/appframework/middleware/security/securitymiddleware.php
index d0b7202a360..725ce689b48 100644
--- a/lib/private/appframework/middleware/security/securitymiddleware.php
+++ b/lib/private/appframework/middleware/security/securitymiddleware.php
@@ -27,7 +27,6 @@
namespace OC\AppFramework\Middleware\Security;
-use OC\AppFramework\Http;
use OC\Appframework\Middleware\Security\Exceptions\AppNotEnabledException;
use OC\Appframework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException;
use OC\Appframework\Middleware\Security\Exceptions\NotAdminException;
diff --git a/lib/private/appframework/utility/controllermethodreflector.php b/lib/private/appframework/utility/controllermethodreflector.php
index 63cf5ac24f0..1118332f930 100644
--- a/lib/private/appframework/utility/controllermethodreflector.php
+++ b/lib/private/appframework/utility/controllermethodreflector.php
@@ -60,16 +60,18 @@ class ControllerMethodReflector implements IControllerMethodReflector{
// extract type parameter information
preg_match_all('/@param\h+(?P<type>\w+)\h+\$(?P<var>\w+)/', $docs, $matches);
- // this is just a fix for PHP 5.3 (array_combine raises warning if called with
- // two empty arrays
- if($matches['var'] === array() && $matches['type'] === array()) {
- $this->types = array();
- } else {
- $this->types = array_combine($matches['var'], $matches['type']);
- }
+ $this->types = array_combine($matches['var'], $matches['type']);
- // get method parameters
foreach ($reflection->getParameters() as $param) {
+ // extract type information from PHP 7 scalar types and prefer them
+ // over phpdoc annotations
+ if (method_exists($param, 'getType')) {
+ $type = $param->getType();
+ if ($type !== null) {
+ $this->types[$param->getName()] = (string) $type;
+ }
+ }
+
if($param->isOptional()) {
$default = $param->getDefaultValue();
} else {
@@ -82,9 +84,9 @@ class ControllerMethodReflector implements IControllerMethodReflector{
/**
* Inspects the PHPDoc parameters for types
- * @param string $parameter the parameter whose type comments should be
+ * @param string $parameter the parameter whose type comments should be
* parsed
- * @return string|null type in the type parameters (@param int $something)
+ * @return string|null type in the type parameters (@param int $something)
* would return int or null if not existing
*/
public function getType($parameter) {
diff --git a/lib/private/archive/tar.php b/lib/private/archive/tar.php
index 4448e56850d..4066e1d86c1 100644
--- a/lib/private/archive/tar.php
+++ b/lib/private/archive/tar.php
@@ -86,7 +86,7 @@ class OC_Archive_TAR extends OC_Archive {
* @return bool
*/
function addFolder($path) {
- $tmpBase = OC_Helper::tmpFolder();
+ $tmpBase = \OC::$server->getTempManager()->getTemporaryFolder();
if (substr($path, -1, 1) != '/') {
$path .= '/';
}
diff --git a/lib/private/avatar.php b/lib/private/avatar.php
index 37a813f3ff8..966e4903649 100644
--- a/lib/private/avatar.php
+++ b/lib/private/avatar.php
@@ -31,6 +31,7 @@ namespace OC;
use OCP\Files\Folder;
use OCP\Files\File;
+use OCP\Files\NotFoundException;
use OCP\IL10N;
use OC_Image;
@@ -62,28 +63,14 @@ class Avatar implements \OCP\IAvatar {
* @return boolean|\OCP\IImage containing the avatar or false if there's no image
*/
public function get ($size = 64) {
- if ($this->folder->nodeExists('avatar.jpg')) {
- $ext = 'jpg';
- } elseif ($this->folder->nodeExists('avatar.png')) {
- $ext = 'png';
- } else {
+ try {
+ $file = $this->getFile($size);
+ } catch (NotFoundException $e) {
return false;
}
$avatar = new OC_Image();
- if ($this->folder->nodeExists('avatar.' . $size . '.' . $ext)) {
- /** @var File $node */
- $node = $this->folder->get('avatar.' . $size . '.' . $ext);
- $avatar->loadFromData($node->getContent());
- } else {
- /** @var File $node */
- $node = $this->folder->get('avatar.' . $ext);
- $avatar->loadFromData($node->getContent());
- if ($size > 0) {
- $avatar->resize($size);
- }
- $this->folder->newFile('avatar.' . $size . '.' . $ext)->putContent($avatar->data());
- }
+ $avatar->loadFromData($file->getContent());
return $avatar;
}
@@ -137,11 +124,59 @@ class Avatar implements \OCP\IAvatar {
* @return void
*/
public function remove () {
+ $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/';
+ $avatars = $this->folder->search('avatar');
+
+ foreach ($avatars as $avatar) {
+ if (preg_match($regex, $avatar->getName())) {
+ $avatar->delete();
+ }
+ }
+ }
+
+ /**
+ * Get the File of an avatar of size $size.
+ *
+ * @param int $size
+ * @return File
+ * @throws NotFoundException
+ */
+ public function getFile($size) {
+ $ext = $this->getExtention();
+
+ $path = 'avatar.' . $size . '.' . $ext;
+
try {
- $this->folder->get('avatar.jpg')->delete();
- } catch (\OCP\Files\NotFoundException $e) {}
- try {
- $this->folder->get('avatar.png')->delete();
- } catch (\OCP\Files\NotFoundException $e) {}
+ $file = $this->folder->get($path);
+ } catch (NotFoundException $e) {
+ if ($size <= 0) {
+ throw new NotFoundException;
+ }
+
+ $avatar = new OC_Image();
+ /** @var File $file */
+ $file = $this->folder->get('avatar.' . $ext);
+ $avatar->loadFromData($file->getContent());
+ $avatar->resize($size);
+ $file = $this->folder->newFile($path);
+ $file->putContent($avatar->data());
+ }
+
+ return $file;
+ }
+
+ /**
+ * Get the extention of the avatar. If there is no avatar throw Exception
+ *
+ * @return string
+ * @throws NotFoundException
+ */
+ private function getExtention() {
+ if ($this->folder->nodeExists('avatar.jpg')) {
+ return 'jpg';
+ } elseif ($this->folder->nodeExists('avatar.png')) {
+ return 'png';
+ }
+ throw new NotFoundException;
}
}
diff --git a/lib/private/backgroundjob/job.php b/lib/private/backgroundjob/job.php
index 88682cd09bb..40a27491fe6 100644
--- a/lib/private/backgroundjob/job.php
+++ b/lib/private/backgroundjob/job.php
@@ -54,7 +54,6 @@ abstract class Job implements IJob {
if ($logger) {
$logger->error('Error while running background job: ' . $e->getMessage());
}
- $jobList->remove($this, $this->argument);
}
}
diff --git a/lib/private/backgroundjob/joblist.php b/lib/private/backgroundjob/joblist.php
index 03c9180ddb0..446de2fa1a4 100644
--- a/lib/private/backgroundjob/joblist.php
+++ b/lib/private/backgroundjob/joblist.php
@@ -24,134 +24,180 @@
namespace OC\BackgroundJob;
+use OCP\AppFramework\QueryException;
+use OCP\BackgroundJob\IJob;
use OCP\BackgroundJob\IJobList;
use OCP\AutoloadNotAllowedException;
class JobList implements IJobList {
- /**
- * @var \OCP\IDBConnection
- */
- private $conn;
+ /** @var \OCP\IDBConnection */
+ protected $connection;
/**
* @var \OCP\IConfig $config
*/
- private $config;
+ protected $config;
/**
- * @param \OCP\IDBConnection $conn
+ * @param \OCP\IDBConnection $connection
* @param \OCP\IConfig $config
*/
- public function __construct($conn, $config) {
- $this->conn = $conn;
+ public function __construct($connection, $config) {
+ $this->connection = $connection;
$this->config = $config;
}
/**
- * @param Job|string $job
+ * @param IJob|string $job
* @param mixed $argument
*/
public function add($job, $argument = null) {
if (!$this->has($job, $argument)) {
- if ($job instanceof Job) {
+ if ($job instanceof IJob) {
$class = get_class($job);
} else {
$class = $job;
}
+
$argument = json_encode($argument);
if (strlen($argument) > 4000) {
throw new \InvalidArgumentException('Background job arguments can\'t exceed 4000 characters (json encoded)');
}
- $query = $this->conn->prepare('INSERT INTO `*PREFIX*jobs`(`class`, `argument`, `last_run`) VALUES(?, ?, 0)');
- $query->execute(array($class, $argument));
+
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('jobs')
+ ->values([
+ 'class' => $query->createNamedParameter($class),
+ 'argument' => $query->createNamedParameter($argument),
+ 'last_run' => $query->createNamedParameter(0, \PDO::PARAM_INT),
+ ]);
+ $query->execute();
}
}
/**
- * @param Job|string $job
+ * @param IJob|string $job
* @param mixed $argument
*/
public function remove($job, $argument = null) {
- if ($job instanceof Job) {
+ if ($job instanceof IJob) {
$class = get_class($job);
} else {
$class = $job;
}
+
+ $query = $this->connection->getQueryBuilder();
+ $query->delete('jobs')
+ ->where($query->expr()->eq('class', $query->createNamedParameter($class)));
if (!is_null($argument)) {
$argument = json_encode($argument);
- $query = $this->conn->prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?');
- $query->execute(array($class, $argument));
- } else {
- $query = $this->conn->prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ?');
- $query->execute(array($class));
+ $query->andWhere($query->expr()->eq('argument', $query->createNamedParameter($argument)));
}
+ $query->execute();
}
+ /**
+ * @param int $id
+ */
protected function removeById($id) {
- $query = $this->conn->prepare('DELETE FROM `*PREFIX*jobs` WHERE `id` = ?');
- $query->execute([$id]);
+ $query = $this->connection->getQueryBuilder();
+ $query->delete('jobs')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($id, \PDO::PARAM_INT)));
+ $query->execute();
}
/**
* check if a job is in the list
*
- * @param Job|string $job
+ * @param IJob|string $job
* @param mixed $argument
* @return bool
*/
public function has($job, $argument) {
- if ($job instanceof Job) {
+ if ($job instanceof IJob) {
$class = get_class($job);
} else {
$class = $job;
}
$argument = json_encode($argument);
- $query = $this->conn->prepare('SELECT `id` FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?');
- $query->execute(array($class, $argument));
- return (bool)$query->fetch();
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('id')
+ ->from('jobs')
+ ->where($query->expr()->eq('class', $query->createNamedParameter($class)))
+ ->andWhere($query->expr()->eq('argument', $query->createNamedParameter($argument)))
+ ->setMaxResults(1);
+
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ return (bool) $row;
}
/**
* get all jobs in the list
*
- * @return Job[]
+ * @return IJob[]
*/
public function getAll() {
- $query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs`');
- $query->execute();
- $jobs = array();
- while ($row = $query->fetch()) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from('jobs');
+ $result = $query->execute();
+
+ $jobs = [];
+ while ($row = $result->fetch()) {
$job = $this->buildJob($row);
if ($job) {
$jobs[] = $job;
}
}
+ $result->closeCursor();
+
return $jobs;
}
/**
* get the next job in the list
*
- * @return Job
+ * @return IJob|null
*/
public function getNext() {
$lastId = $this->getLastJob();
- $query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` > ? ORDER BY `id` ASC', 1);
- $query->execute(array($lastId));
- if ($row = $query->fetch()) {
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from('jobs')
+ ->where($query->expr()->gt('id', $query->createNamedParameter($lastId, \PDO::PARAM_INT)))
+ ->orderBy('id', 'ASC')
+ ->setMaxResults(1);
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
$jobId = $row['id'];
$job = $this->buildJob($row);
} else {
//begin at the start of the queue
- $query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` ORDER BY `id` ASC', 1);
- $query->execute();
- if ($row = $query->fetch()) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from('jobs')
+ ->orderBy('id', 'ASC')
+ ->setMaxResults(1);
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
$jobId = $row['id'];
$job = $this->buildJob($row);
} else {
return null; //empty job list
}
}
+
if (is_null($job)) {
$this->removeById($jobId);
return $this->getNext();
@@ -162,12 +208,18 @@ class JobList implements IJobList {
/**
* @param int $id
- * @return Job|null
+ * @return IJob|null
*/
public function getById($id) {
- $query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` = ?');
- $query->execute(array($id));
- if ($row = $query->fetch()) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from('jobs')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($id, \PDO::PARAM_INT)));
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
return $this->buildJob($row);
} else {
return null;
@@ -178,33 +230,38 @@ class JobList implements IJobList {
* get the job object from a row in the db
*
* @param array $row
- * @return Job
+ * @return IJob|null
*/
private function buildJob($row) {
- $class = $row['class'];
- /**
- * @var Job $job
- */
try {
- if (!class_exists($class)) {
- // job from disabled app or old version of an app, no need to do anything
- return null;
+ try {
+ // Try to load the job as a service
+ /** @var IJob $job */
+ $job = \OC::$server->query($row['class']);
+ } catch (QueryException $e) {
+ if (class_exists($row['class'])) {
+ $class = $row['class'];
+ $job = new $class();
+ } else {
+ // job from disabled app or old version of an app, no need to do anything
+ return null;
+ }
}
- $job = new $class();
+
$job->setId($row['id']);
$job->setLastRun($row['last_run']);
$job->setArgument(json_decode($row['argument'], true));
return $job;
} catch (AutoloadNotAllowedException $e) {
// job is from a disabled app, ignore
+ return null;
}
- return null;
}
/**
* set the job that was last ran
*
- * @param Job $job
+ * @param IJob $job
*/
public function setLastJob($job) {
$this->config->setAppValue('backgroundjob', 'lastjob', $job->getId());
@@ -213,19 +270,22 @@ class JobList implements IJobList {
/**
* get the id of the last ran job
*
- * @return string
+ * @return int
*/
public function getLastJob() {
- return $this->config->getAppValue('backgroundjob', 'lastjob', 0);
+ return (int) $this->config->getAppValue('backgroundjob', 'lastjob', 0);
}
/**
* set the lastRun of $job to now
*
- * @param Job $job
+ * @param IJob $job
*/
public function setLastRun($job) {
- $query = $this->conn->prepare('UPDATE `*PREFIX*jobs` SET `last_run` = ? WHERE `id` = ?');
- $query->execute(array(time(), $job->getId()));
+ $query = $this->connection->getQueryBuilder();
+ $query->update('jobs')
+ ->set('last_run', $query->createNamedParameter(time(), \PDO::PARAM_INT))
+ ->where($query->expr()->eq('id', $query->createNamedParameter($job->getId(), \PDO::PARAM_INT)));
+ $query->execute();
}
}
diff --git a/lib/private/db.php b/lib/private/db.php
index a4a7b7d17d4..d47b7d4f31a 100644
--- a/lib/private/db.php
+++ b/lib/private/db.php
@@ -36,13 +36,6 @@
class OC_DB {
/**
- * @return \OCP\IDBConnection
- */
- static public function getConnection() {
- return \OC::$server->getDatabaseConnection();
- }
-
- /**
* get MDB2 schema manager
*
* @return \OC\DB\MDB2SchemaManager
@@ -158,42 +151,6 @@ class OC_DB {
}
/**
- * gets last value of autoincrement
- * @param string $table The optional table name (will replace *PREFIX*) and add sequence suffix
- * @return string id
- * @throws \OC\DatabaseException
- *
- * \Doctrine\DBAL\Connection lastInsertId
- *
- * Call this method right after the insert command or other functions may
- * cause trouble!
- */
- public static function insertid($table=null) {
- return \OC::$server->getDatabaseConnection()->lastInsertId($table);
- }
-
- /**
- * Start a transaction
- */
- public static function beginTransaction() {
- return \OC::$server->getDatabaseConnection()->beginTransaction();
- }
-
- /**
- * Commit the database changes done during a transaction that is in progress
- */
- public static function commit() {
- return \OC::$server->getDatabaseConnection()->commit();
- }
-
- /**
- * Rollback the database changes done during a transaction that is in progress
- */
- public static function rollback() {
- return \OC::$server->getDatabaseConnection()->rollback();
- }
-
- /**
* saves database schema to xml file
* @param string $file name of file
* @param int $mode
@@ -254,15 +211,6 @@ class OC_DB {
}
/**
- * drop a table - the database prefix will be prepended
- * @param string $tableName the table to drop
- */
- public static function dropTable($tableName) {
- $connection = \OC::$server->getDatabaseConnection();
- $connection->dropTable($tableName);
- }
-
- /**
* remove all tables defined in a database structure xml file
* @param string $file the xml file describing the tables
*/
@@ -272,15 +220,6 @@ class OC_DB {
}
/**
- * check if a result is an error, works with Doctrine
- * @param mixed $result
- * @return bool
- */
- public static function isError($result) {
- //Doctrine returns false on error (and throws an exception)
- return $result === false;
- }
- /**
* check if a result is an error and throws an exception, works with \Doctrine\DBAL\DBALException
* @param mixed $result
* @param string $message
@@ -288,20 +227,16 @@ class OC_DB {
* @throws \OC\DatabaseException
*/
public static function raiseExceptionOnError($result, $message = null) {
- if(self::isError($result)) {
+ if($result === false) {
if ($message === null) {
$message = self::getErrorMessage();
} else {
$message .= ', Root cause:' . self::getErrorMessage();
}
- throw new \OC\DatabaseException($message, self::getErrorCode());
+ throw new \OC\DatabaseException($message, \OC::$server->getDatabaseConnection()->errorCode());
}
}
- public static function getErrorCode() {
- $connection = \OC::$server->getDatabaseConnection();
- return $connection->errorCode();
- }
/**
* returns the error code and message as a string for logging
* works with DoctrineException
diff --git a/lib/private/defaults.php b/lib/private/defaults.php
index 16f45943f54..23f0baad96e 100644
--- a/lib/private/defaults.php
+++ b/lib/private/defaults.php
@@ -49,7 +49,7 @@ class OC_Defaults {
function __construct() {
$this->l = \OC::$server->getL10N('lib');
- $version = OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
$this->defaultEntity = 'ownCloud'; /* e.g. company name, used for footers and copyright notices */
$this->defaultName = 'ownCloud'; /* short name, used when referring to the software */
diff --git a/lib/private/eventsource.php b/lib/private/eventsource.php
index c076b87ddd9..0e98bdc2628 100644
--- a/lib/private/eventsource.php
+++ b/lib/private/eventsource.php
@@ -76,7 +76,7 @@ class OC_EventSource implements \OCP\IEventSource {
} else {
header("Content-Type: text/event-stream");
}
- if (!OC_Util::isCallRegistered()) {
+ if (!(\OC::$server->getRequest()->passesCSRFCheck())) {
$this->send('error', 'Possible CSRF attack. Connection will be closed.');
$this->close();
exit();
diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php
index 983e12d7639..88bb57d2b5c 100644
--- a/lib/private/files/cache/scanner.php
+++ b/lib/private/files/cache/scanner.php
@@ -336,7 +336,7 @@ class Scanner extends BasicEmitter {
$newChildren = $this->getNewChildren($path);
if ($this->useTransactions) {
- \OC_DB::beginTransaction();
+ \OC::$server->getDatabaseConnection()->beginTransaction();
}
$exceptionOccurred = false;
foreach ($newChildren as $file) {
@@ -361,7 +361,7 @@ class Scanner extends BasicEmitter {
$exceptionOccurred = true;
} catch (\OCP\Lock\LockedException $e) {
if ($this->useTransactions) {
- \OC_DB::rollback();
+ \OC::$server->getDatabaseConnection()->rollback();
}
throw $e;
}
@@ -372,7 +372,7 @@ class Scanner extends BasicEmitter {
$this->removeFromCache($child);
}
if ($this->useTransactions) {
- \OC_DB::commit();
+ \OC::$server->getDatabaseConnection()->commit();
}
if ($exceptionOccurred) {
// It might happen that the parallel scan process has already
diff --git a/lib/private/files/cache/storage.php b/lib/private/files/cache/storage.php
index cee69194095..4998c622e84 100644
--- a/lib/private/files/cache/storage.php
+++ b/lib/private/files/cache/storage.php
@@ -58,10 +58,10 @@ class Storage {
if ($row = self::getStorageById($this->storageId)) {
$this->numericId = $row['numeric_id'];
} else {
- $connection = \OC_DB::getConnection();
+ $connection = \OC::$server->getDatabaseConnection();
$available = $isAvailable ? 1 : 0;
if ($connection->insertIfNotExist('*PREFIX*storages', ['id' => $this->storageId, 'available' => $available])) {
- $this->numericId = \OC_DB::insertid('*PREFIX*storages');
+ $this->numericId = $connection->lastInsertId('*PREFIX*storages');
} else {
if ($row = self::getStorageById($this->storageId)) {
$this->numericId = $row['numeric_id'];
diff --git a/lib/private/files/objectstore/objectstorestorage.php b/lib/private/files/objectstore/objectstorestorage.php
index 5ec05a3529e..b34a6bdfb84 100644
--- a/lib/private/files/objectstore/objectstorestorage.php
+++ b/lib/private/files/objectstore/objectstorestorage.php
@@ -274,7 +274,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
} else {
$ext = '';
}
- $tmpFile = \OC_Helper::tmpFile($ext);
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
if ($this->file_exists($path)) {
$source = $this->fopen($path, 'r');
@@ -329,7 +329,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
$stat['mtime'] = $mtime;
$this->getCache()->update($stat['fileid'], $stat);
} else {
- $mimeType = \OC_Helper::getFileNameMimeType($path);
+ $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
// create new file
$stat = array(
'etag' => $this->getETag($path),
diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php
index b06543d0a6a..1e30d48f613 100644
--- a/lib/private/files/storage/common.php
+++ b/lib/private/files/storage/common.php
@@ -225,7 +225,7 @@ abstract class Common implements Storage {
if ($this->is_dir($path)) {
return 'httpd/unix-directory';
} elseif ($this->file_exists($path)) {
- return \OC_Helper::getFileNameMimeType($path);
+ return \OC::$server->getMimeTypeDetector()->detectPath($path);
} else {
return false;
}
@@ -248,7 +248,7 @@ abstract class Common implements Storage {
}
public function getLocalFolder($path) {
- $baseDir = \OC_Helper::tmpFolder();
+ $baseDir = \OC::$server->getTempManager()->getTemporaryFolder();
$this->addLocalFolder($path, $baseDir);
return $baseDir;
}
diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php
index dda163e41a0..9afebab1dd7 100644
--- a/lib/private/files/storage/dav.php
+++ b/lib/private/files/storage/dav.php
@@ -34,6 +34,7 @@
namespace OC\Files\Storage;
use Exception;
+use GuzzleHttp\Exception\RequestException;
use OC\Files\Filesystem;
use OC\Files\Stream\Close;
use Icewind\Streams\IteratorDirectory;
@@ -339,15 +340,20 @@ class DAV extends Common {
switch ($mode) {
case 'r':
case 'rb':
- if (!$this->file_exists($path)) {
- return false;
+ try {
+ $response = $this->httpClientService
+ ->newClient()
+ ->get($this->createBaseUri() . $this->encodePath($path), [
+ 'auth' => [$this->user, $this->password],
+ 'stream' => true
+ ]);
+ } catch (RequestException $e) {
+ if ($e->getResponse()->getStatusCode() === 404) {
+ return false;
+ } else {
+ throw $e;
+ }
}
- $response = $this->httpClientService
- ->newClient()
- ->get($this->createBaseUri() . $this->encodePath($path), [
- 'auth' => [$this->user, $this->password],
- 'stream' => true
- ]);
if ($response->getStatusCode() !== Http::STATUS_OK) {
if ($response->getStatusCode() === Http::STATUS_LOCKED) {
diff --git a/lib/private/files/storage/localtempfiletrait.php b/lib/private/files/storage/localtempfiletrait.php
index 84331f49b19..8875c2c4493 100644
--- a/lib/private/files/storage/localtempfiletrait.php
+++ b/lib/private/files/storage/localtempfiletrait.php
@@ -70,7 +70,7 @@ trait LocalTempFileTrait {
} else {
$extension = '';
}
- $tmpFile = \OC_Helper::tmpFile($extension);
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
$target = fopen($tmpFile, 'w');
\OC_Helper::streamCopy($source, $target);
fclose($target);
diff --git a/lib/private/files/storage/temporary.php b/lib/private/files/storage/temporary.php
index c8b99a55637..8abc19929b0 100644
--- a/lib/private/files/storage/temporary.php
+++ b/lib/private/files/storage/temporary.php
@@ -29,7 +29,7 @@ namespace OC\Files\Storage;
*/
class Temporary extends Local{
public function __construct($arguments = null) {
- parent::__construct(array('datadir' => \OC_Helper::tmpFolder()));
+ parent::__construct(array('datadir' => \OC::$server->getTempManager()->getTemporaryFolder()));
}
public function cleanUp() {
diff --git a/lib/private/files/type/detection.php b/lib/private/files/type/detection.php
index c102e739e04..0e2bab39e5b 100644
--- a/lib/private/files/type/detection.php
+++ b/lib/private/files/type/detection.php
@@ -238,7 +238,7 @@ class Detection implements IMimeTypeDetector {
$finfo = finfo_open(FILEINFO_MIME);
return finfo_buffer($finfo, $data);
} else {
- $tmpFile = \OC_Helper::tmpFile();
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
$fh = fopen($tmpFile, 'wb');
fwrite($fh, $data, 8024);
fclose($fh);
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index b8b1b8a50d6..357f854e5e2 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -86,6 +86,8 @@ class View {
private $updaterEnabled = true;
+ private $userManager;
+
/**
* @param string $root
* @throws \Exception If $root contains an invalid path
@@ -101,6 +103,7 @@ class View {
$this->fakeRoot = $root;
$this->lockingProvider = \OC::$server->getLockingProvider();
$this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
+ $this->userManager = \OC::$server->getUserManager();
}
public function getAbsolutePath($path = '/') {
@@ -912,7 +915,7 @@ class View {
$source = $this->fopen($path, 'r');
if ($source) {
$extension = pathinfo($path, PATHINFO_EXTENSION);
- $tmpFile = \OC_Helper::tmpFile($extension);
+ $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
file_put_contents($tmpFile, $source);
return $tmpFile;
} else {
@@ -1196,7 +1199,7 @@ class View {
* @return \OC\User\User
*/
private function getUserObjectForOwner($ownerId) {
- $owner = \OC::$server->getUserManager()->get($ownerId);
+ $owner = $this->userManager->get($ownerId);
if ($owner instanceof IUser) {
return $owner;
} else {
@@ -1339,11 +1342,12 @@ class View {
$folderId = $data['fileid'];
$contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
+ $sharingDisabled = \OCP\Util::isSharingDisabledForUser();
/**
* @var \OC\Files\FileInfo[] $files
*/
- $files = array_map(function (array $content) use ($path, $storage, $mount) {
- if (\OCP\Util::isSharingDisabledForUser()) {
+ $files = array_map(function (array $content) use ($path, $storage, $mount, $sharingDisabled) {
+ if ($sharingDisabled) {
$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
}
$owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
diff --git a/lib/private/helper.php b/lib/private/helper.php
index 78a567638ef..64952903712 100644
--- a/lib/private/helper.php
+++ b/lib/private/helper.php
@@ -54,88 +54,6 @@ class OC_Helper {
private static $templateManager;
/**
- * Creates an url using a defined route
- * @param string $route
- * @param array $parameters with param=>value, will be appended to the returned url
- * @return string the url
- * @deprecated Use \OC::$server->getURLGenerator()->linkToRoute($route, $parameters)
- *
- * Returns a url to the given app and file.
- */
- public static function linkToRoute($route, $parameters = array()) {
- return OC::$server->getURLGenerator()->linkToRoute($route, $parameters);
- }
-
- /**
- * Creates an url
- * @param string $app app
- * @param string $file file
- * @param array $args array with param=>value, will be appended to the returned url
- * The value of $args will be urlencoded
- * @return string the url
- * @deprecated Use \OC::$server->getURLGenerator()->linkTo($app, $file, $args)
- *
- * Returns a url to the given app and file.
- */
- public static function linkTo( $app, $file, $args = array() ) {
- return OC::$server->getURLGenerator()->linkTo($app, $file, $args);
- }
-
- /**
- * Creates an absolute url
- * @param string $app app
- * @param string $file file
- * @param array $args array with param=>value, will be appended to the returned url
- * The value of $args will be urlencoded
- * @return string the url
- *
- * Returns a absolute url to the given app and file.
- */
- public static function linkToAbsolute($app, $file, $args = array()) {
- return OC::$server->getURLGenerator()->getAbsoluteURL(
- self::linkTo($app, $file, $args)
- );
- }
-
- /**
- * Makes an $url absolute
- * @param string $url the url
- * @return string the absolute url
- * @deprecated Use \OC::$server->getURLGenerator()->getAbsoluteURL($url)
- *
- * Returns a absolute url to the given app and file.
- */
- public static function makeURLAbsolute($url) {
- return OC::$server->getURLGenerator()->getAbsoluteURL($url);
- }
-
- /**
- * Creates an url for remote use
- * @param string $service id
- * @return string the url
- *
- * Returns a url to the given service.
- */
- public static function linkToRemoteBase($service) {
- return self::linkTo('', 'remote.php') . '/' . $service;
- }
-
- /**
- * Creates an absolute url for remote use
- * @param string $service id
- * @param bool $add_slash
- * @return string the url
- *
- * Returns a absolute url to the given service.
- */
- public static function linkToRemote($service, $add_slash = true) {
- return OC::$server->getURLGenerator()->getAbsoluteURL(
- self::linkToRemoteBase($service)
- . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : '')
- );
- }
-
- /**
* Creates an absolute url for public use
* @param string $service id
* @param bool $add_slash
@@ -147,7 +65,7 @@ class OC_Helper {
if ($service === 'files') {
$url = OC::$server->getURLGenerator()->getAbsoluteURL('/s');
} else {
- $url = OC::$server->getURLGenerator()->getAbsoluteURL(self::linkTo('', 'public.php').'?service='.$service);
+ $url = OC::$server->getURLGenerator()->getAbsoluteURL(OC::$server->getURLGenerator()->linkTo('', 'public.php').'?service='.$service);
}
return $url . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : '');
}
@@ -166,18 +84,6 @@ class OC_Helper {
}
/**
- * get path to icon of file type
- * @param string $mimetype mimetype
- * @return string the url
- *
- * Returns the path to the image of this file type.
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->mimeTypeIcon($mimetype)
- */
- public static function mimetypeIcon($mimetype) {
- return \OC::$server->getMimeTypeDetector()->mimeTypeIcon($mimetype);
- }
-
- /**
* get path to preview of file
* @param string $path path
* @return string the url
@@ -185,21 +91,11 @@ class OC_Helper {
* Returns the path to the preview of the file.
*/
public static function previewIcon($path) {
- return self::linkToRoute( 'core_ajax_preview', array('x' => 32, 'y' => 32, 'file' => $path ));
+ return \OC::$server->getURLGenerator()->linkToRoute('core_ajax_preview', ['x' => 32, 'y' => 32, 'file' => $path]);
}
public static function publicPreviewIcon( $path, $token ) {
- return self::linkToRoute( 'core_ajax_public_preview', array('x' => 32, 'y' => 32, 'file' => $path, 't' => $token));
- }
-
- /**
- * shows whether the user has an avatar
- * @param string $user username
- * @return bool avatar set or not
- * @deprecated 9.0.0 Use \OC::$server->getAvatarManager()->getAvatar($user)->exists();
- **/
- public static function userAvatarSet($user) {
- return \OC::$server->getAvatarManager()->getAvatar($user)->exists();
+ return \OC::$server->getURLGenerator()->linkToRoute('core_ajax_public_preview', ['x' => 32, 'y' => 32, 'file' => $path, 't' => $token]);
}
/**
@@ -364,14 +260,6 @@ class OC_Helper {
}
/**
- * @return \OC\Files\Type\Detection
- * @deprecated 8.2.0 use \OC::$server->getMimeTypeDetector()
- */
- static public function getMimetypeDetector() {
- return \OC::$server->getMimeTypeDetector();
- }
-
- /**
* @return \OC\Files\Type\TemplateManager
*/
static public function getFileTemplateManager() {
@@ -382,39 +270,6 @@ class OC_Helper {
}
/**
- * Try to guess the mimetype based on filename
- *
- * @param string $path
- * @return string
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->detectPath($path)
- */
- static public function getFileNameMimeType($path) {
- return \OC::$server->getMimeTypeDetector()->detectPath($path);
- }
-
- /**
- * Get a secure mimetype that won't expose potential XSS.
- *
- * @param string $mimeType
- * @return string
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType)
- */
- static function getSecureMimeType($mimeType) {
- return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
- }
-
- /**
- * get the mimetype form a data string
- *
- * @param string $data
- * @return string
- * @deprecated 8.2.0 Use \OC::$server->getMimeTypeDetector()->detectString($data)
- */
- static function getStringMimeType($data) {
- return \OC::$server->getMimeTypeDetector()->detectString($data);
- }
-
- /**
* detect if a given program is found in the search PATH
*
* @param string $name
@@ -493,31 +348,6 @@ class OC_Helper {
}
/**
- * create a temporary file with an unique filename
- *
- * @param string $postfix
- * @return string
- * @deprecated Use the TempManager instead
- *
- * temporary files are automatically cleaned up after the script is finished
- */
- public static function tmpFile($postfix = '') {
- return \OC::$server->getTempManager()->getTemporaryFile($postfix);
- }
-
- /**
- * create a temporary folder with an unique filename
- *
- * @return string
- * @deprecated Use the TempManager instead
- *
- * temporary files are automatically cleaned up after the script is finished
- */
- public static function tmpFolder() {
- return \OC::$server->getTempManager()->getTemporaryFolder();
- }
-
- /**
* Adds a suffix to the name in case the file exists
*
* @param string $path
@@ -782,7 +612,7 @@ class OC_Helper {
*/
public static function getStorageInfo($path, $rootInfo = null) {
// return storage info without adding mount points
- $includeExtStorage = \OC_Config::getValue('quota_include_external_storage', false);
+ $includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
if (!$rootInfo) {
$rootInfo = \OC\Files\Filesystem::getFileInfo($path, false);
diff --git a/lib/private/image.php b/lib/private/image.php
index 4ca9b811100..a5de7e86b94 100644
--- a/lib/private/image.php
+++ b/lib/private/image.php
@@ -39,17 +39,19 @@
* Class for basic image manipulation
*/
class OC_Image implements \OCP\IImage {
+ /** @var false|resource */
protected $resource = false; // tmp resource.
+ /** @var int */
protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident.
- protected $mimeType = "image/png"; // Default to png
+ /** @var string */
+ protected $mimeType = 'image/png'; // Default to png
+ /** @var int */
protected $bitDepth = 24;
+ /** @var null|string */
protected $filePath = null;
-
+ /** @var finfo */
private $fileInfo;
-
- /**
- * @var \OCP\ILogger
- */
+ /** @var \OCP\ILogger */
private $logger;
/**
diff --git a/lib/private/installer.php b/lib/private/installer.php
index fa9fc6704df..bbd976cda91 100644
--- a/lib/private/installer.php
+++ b/lib/private/installer.php
@@ -232,8 +232,8 @@ class OC_Installer{
\OC::$server->getConfig(),
\OC::$server->getLogger()
);
- $appData = $ocsClient->getApplication($ocsId, \OC_Util::getVersion());
- $download = $ocsClient->getApplicationDownload($ocsId, \OC_Util::getVersion());
+ $appData = $ocsClient->getApplication($ocsId, \OCP\Util::getVersion());
+ $download = $ocsClient->getApplicationDownload($ocsId, \OCP\Util::getVersion());
if (isset($download['downloadlink']) && trim($download['downloadlink']) !== '') {
$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
@@ -264,7 +264,7 @@ class OC_Installer{
//download the file if necessary
if($data['source']=='http') {
$pathInfo = pathinfo($data['href']);
- $path=OC_Helper::tmpFile('.' . $pathInfo['extension']);
+ $path = \OC::$server->getTempManager()->getTemporaryFile('.' . $pathInfo['extension']);
if(!isset($data['href'])) {
throw new \Exception($l->t("No href specified when installing app from http"));
}
@@ -284,7 +284,7 @@ class OC_Installer{
}
//extract the archive in a temporary folder
- $extractDir=OC_Helper::tmpFolder();
+ $extractDir = \OC::$server->getTempManager()->getTemporaryFolder();
OC_Helper::rmdirr($extractDir);
mkdir($extractDir);
if($archive=OC_Archive::open($path)) {
@@ -342,7 +342,7 @@ class OC_Installer{
}
// check if the app is compatible with this version of ownCloud
- if(!OC_App::isAppCompatible(OC_Util::getVersion(), $info)) {
+ if(!OC_App::isAppCompatible(\OCP\Util::getVersion(), $info)) {
OC_Helper::rmdirr($extractDir);
throw new \Exception($l->t("App can't be installed because it is not compatible with this version of ownCloud"));
}
@@ -400,7 +400,7 @@ class OC_Installer{
\OC::$server->getConfig(),
\OC::$server->getLogger()
);
- $ocsdata = $ocsClient->getApplication($ocsid, \OC_Util::getVersion());
+ $ocsdata = $ocsClient->getApplication($ocsid, \OCP\Util::getVersion());
$ocsversion= (string) $ocsdata['version'];
$currentversion=OC_App::getAppVersion($app);
if (version_compare($ocsversion, $currentversion, '>')) {
diff --git a/lib/private/json.php b/lib/private/json.php
index eba374f4da2..0bf4e8bcd01 100644
--- a/lib/private/json.php
+++ b/lib/private/json.php
@@ -76,7 +76,7 @@ class OC_JSON{
* @deprecated Use annotation based CSRF checks from the AppFramework instead
*/
public static function callCheck() {
- if( !OC_Util::isCallRegistered()) {
+ if( !(\OC::$server->getRequest()->passesCSRFCheck())) {
$l = \OC::$server->getL10N('lib');
self::error(array( 'data' => array( 'message' => $l->t('Token expired. Please reload page.'), 'error' => 'token_expired' )));
exit();
diff --git a/lib/private/legacy/config.php b/lib/private/legacy/config.php
deleted file mode 100644
index 1835d4a4b1c..00000000000
--- a/lib/private/legacy/config.php
+++ /dev/null
@@ -1,94 +0,0 @@
-<?php
-/**
- * @author Bart Visscher <bartv@thisnet.nl>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Michael Gapczynski <GapczynskiM@gmail.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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/>
- *
- */
-
-/**
- * This class is responsible for reading and writing config.php, the very basic
- * configuration file of ownCloud.
- *
- * @deprecated use \OC::$server->getConfig() to get an \OCP\Config instance
- */
-class OC_Config {
-
- /** @var \OC\Config */
- public static $object;
-
- /**
- * Lists all available config keys
- * @return array an array of key names
- *
- * This function returns all keys saved in config.php. Please note that it
- * does not return the values.
- */
- public static function getKeys() {
- return self::$object->getKeys();
- }
-
- /**
- * Gets a value from config.php
- * @param string $key key
- * @param mixed $default = null default value
- * @return mixed the value or $default
- *
- * This function gets the value from config.php. If it does not exist,
- * $default will be returned.
- */
- public static function getValue($key, $default = null) {
- return self::$object->getValue($key, $default);
- }
-
- /**
- * Sets a value
- * @param string $key key
- * @param mixed $value value
- *
- * This function sets the value and writes the config.php.
- *
- */
- public static function setValue($key, $value) {
- self::$object->setValue($key, $value);
- }
-
- /**
- * Sets and deletes values and writes the config.php
- *
- * @param array $configs Associative array with `key => value` pairs
- * If value is null, the config key will be deleted
- */
- public static function setValues(array $configs) {
- self::$object->setValues($configs);
- }
-
- /**
- * Removes a key from the config
- * @param string $key key
- *
- * This function removes a key from the config.php.
- */
- public static function deleteKey($key) {
- self::$object->deleteKey($key);
- }
-}
diff --git a/lib/private/log.php b/lib/private/log.php
index ee5d61e98df..a722243dc69 100644
--- a/lib/private/log.php
+++ b/lib/private/log.php
@@ -227,7 +227,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 && StringUtils::equals($request->getParam('log_secret'), $logCondition['shared_secret'])) {
+ if($request && hash_equals($logCondition['shared_secret'], $request->getParam('log_secret'))) {
$this->logConditionSatisfied = true;
}
}
diff --git a/lib/private/log/owncloud.php b/lib/private/log/owncloud.php
index f8a5f7534c5..e455824a8dd 100644
--- a/lib/private/log/owncloud.php
+++ b/lib/private/log/owncloud.php
@@ -73,7 +73,7 @@ class OC_Log_Owncloud {
} catch (Exception $e) {
$timezone = new DateTimeZone('UTC');
}
- $time = DateTime::createFromFormat("U.u", microtime(true), $timezone);
+ $time = DateTime::createFromFormat("U.u", number_format(microtime(true), 4, ".", ""), $timezone);
if ($time === false) {
$time = new DateTime(null, $timezone);
}
@@ -101,6 +101,9 @@ class OC_Log_Owncloud {
// Fall back to error_log
error_log($entry);
}
+ if (php_sapi_name() === 'cli-server') {
+ error_log($message, 4);
+ }
}
/**
diff --git a/lib/private/memcache/apcu.php b/lib/private/memcache/apcu.php
index 84147233ef0..778e27d4567 100644
--- a/lib/private/memcache/apcu.php
+++ b/lib/private/memcache/apcu.php
@@ -24,7 +24,101 @@
namespace OC\Memcache;
-class APCu extends APC {
+use OCP\IMemcache;
+
+class APCu extends Cache implements IMemcache {
+ use CASTrait {
+ cas as casEmulated;
+ }
+
+ use CADTrait;
+
+ public function get($key) {
+ $result = apcu_fetch($this->getPrefix() . $key, $success);
+ if (!$success) {
+ return null;
+ }
+ return $result;
+ }
+
+ public function set($key, $value, $ttl = 0) {
+ return apcu_store($this->getPrefix() . $key, $value, $ttl);
+ }
+
+ public function hasKey($key) {
+ return apcu_exists($this->getPrefix() . $key);
+ }
+
+ public function remove($key) {
+ return apcu_delete($this->getPrefix() . $key);
+ }
+
+ public function clear($prefix = '') {
+ $ns = $this->getPrefix() . $prefix;
+ $ns = preg_quote($ns, '/');
+ if(class_exists('\APCIterator')) {
+ $iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
+ } else {
+ $iter = new \APCUIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
+ }
+ return apcu_delete($iter);
+ }
+
+ /**
+ * Set a value in the cache if it's not already stored
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
+ * @return bool
+ */
+ public function add($key, $value, $ttl = 0) {
+ return apcu_add($this->getPrefix() . $key, $value, $ttl);
+ }
+
+ /**
+ * Increase a stored number
+ *
+ * @param string $key
+ * @param int $step
+ * @return int | bool
+ */
+ public function inc($key, $step = 1) {
+ $this->add($key, 0);
+ return apcu_inc($this->getPrefix() . $key, $step);
+ }
+
+ /**
+ * Decrease a stored number
+ *
+ * @param string $key
+ * @param int $step
+ * @return int | bool
+ */
+ public function dec($key, $step = 1) {
+ return apcu_dec($this->getPrefix() . $key, $step);
+ }
+
+ /**
+ * Compare and set
+ *
+ * @param string $key
+ * @param mixed $old
+ * @param mixed $new
+ * @return bool
+ */
+ public function cas($key, $old, $new) {
+ // apc only does cas for ints
+ if (is_int($old) and is_int($new)) {
+ return apcu_cas($this->getPrefix() . $key, $old, $new);
+ } else {
+ return $this->casEmulated($key, $old, $new);
+ }
+ }
+
+ /**
+ * @return bool
+ */
static public function isAvailable() {
if (!extension_loaded('apcu')) {
return false;
@@ -32,7 +126,10 @@ class APCu extends APC {
return false;
} elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
return false;
- } elseif (version_compare(phpversion('apc'), '4.0.6') === -1) {
+ } elseif (
+ version_compare(phpversion('apc'), '4.0.6') === -1 &&
+ version_compare(phpversion('apcu'), '5.1.0') === -1
+ ) {
return false;
} else {
return true;
diff --git a/lib/private/ocs/cloud.php b/lib/private/ocs/cloud.php
index 2cf40c449ff..1b04f43d477 100644
--- a/lib/private/ocs/cloud.php
+++ b/lib/private/ocs/cloud.php
@@ -26,7 +26,7 @@ class OC_OCS_Cloud {
public static function getCapabilities() {
$result = array();
- list($major, $minor, $micro) = OC_Util::getVersion();
+ list($major, $minor, $micro) = \OCP\Util::getVersion();
$result['version'] = array(
'major' => $major,
'minor' => $minor,
diff --git a/lib/private/ocsclient.php b/lib/private/ocsclient.php
index e2973f82605..81c9abee058 100644
--- a/lib/private/ocsclient.php
+++ b/lib/private/ocsclient.php
@@ -97,6 +97,7 @@ class OCSClient {
libxml_disable_entity_loader($loadEntities);
if($data === false) {
+ libxml_clear_errors();
$this->logger->error(
sprintf('Could not get %s, content was no valid XML', $action),
[
diff --git a/lib/private/preview.php b/lib/private/preview.php
index 38c043030fc..44d38b354a9 100644
--- a/lib/private/preview.php
+++ b/lib/private/preview.php
@@ -1168,7 +1168,7 @@ class Preview {
*/
private function getMimeIcon() {
$image = new \OC_Image();
- $mimeIconWebPath = \OC_Helper::mimetypeIcon($this->mimeType);
+ $mimeIconWebPath = \OC::$server->getMimeTypeDetector()->mimeTypeIcon($this->mimeType);
if (empty(\OC::$WEBROOT)) {
$mimeIconServerPath = \OC::$SERVERROOT . $mimeIconWebPath;
} else {
diff --git a/lib/private/preview/movie.php b/lib/private/preview/movie.php
index f71eaaf3eb2..2c2e6d09399 100644
--- a/lib/private/preview/movie.php
+++ b/lib/private/preview/movie.php
@@ -46,7 +46,7 @@ class Movie extends Provider {
if ($useFileDirectly) {
$absPath = $fileview->getLocalFile($path);
} else {
- $absPath = \OC_Helper::tmpFile();
+ $absPath = \OC::$server->getTempManager()->getTemporaryFile();
$handle = $fileview->fopen($path, 'rb');
@@ -79,7 +79,7 @@ class Movie extends Provider {
* @return bool|\OCP\IImage
*/
private function generateThumbNail($maxX, $maxY, $absPath, $second) {
- $tmpPath = \OC_Helper::tmpFile();
+ $tmpPath = \OC::$server->getTempManager()->getTemporaryFile();
if (self::$avconvBinary) {
$cmd = self::$avconvBinary . ' -an -y -ss ' . escapeshellarg($second) .
diff --git a/lib/private/repair.php b/lib/private/repair.php
index d870b472c4f..269fe4c5f09 100644
--- a/lib/private/repair.php
+++ b/lib/private/repair.php
@@ -136,10 +136,11 @@ class Repair extends BasicEmitter {
* @return array of RepairStep instances
*/
public static function getBeforeUpgradeRepairSteps() {
+ $connection = \OC::$server->getDatabaseConnection();
$steps = [
new InnoDB(),
- new Collation(\OC::$server->getConfig(), \OC_DB::getConnection()),
- new SqliteAutoincrement(\OC_DB::getConnection()),
+ new Collation(\OC::$server->getConfig(), $connection),
+ new SqliteAutoincrement($connection),
new SearchLuceneTables(),
];
diff --git a/lib/private/repair/assetcache.php b/lib/private/repair/assetcache.php
new file mode 100644
index 00000000000..c46aa63a3e4
--- /dev/null
+++ b/lib/private/repair/assetcache.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * @author Adam Williamson <awilliam@redhat.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OC\Hooks\BasicEmitter;
+
+class AssetCache extends BasicEmitter implements \OC\RepairStep {
+
+ public function getName() {
+ return 'Clear asset cache after upgrade';
+ }
+
+ public function run() {
+ if (!\OC_Template::isAssetPipelineEnabled()) {
+ $this->emit('\OC\Repair', 'info', array('Asset pipeline disabled -> nothing to do'));
+ return;
+ }
+ $assetDir = \OC::$server->getConfig()->getSystemValue('assetdirectory', \OC::$SERVERROOT) . '/assets';
+ \OC_Helper::rmdirr($assetDir, false);
+ $this->emit('\OC\Repair', 'info', array('Asset cache cleared.'));
+ }
+}
+
diff --git a/lib/private/repair/cleantags.php b/lib/private/repair/cleantags.php
new file mode 100644
index 00000000000..d16a49fbca7
--- /dev/null
+++ b/lib/private/repair/cleantags.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IDBConnection;
+
+/**
+ * Class RepairConfig
+ *
+ * @package OC\Repair
+ */
+class CleanTags extends BasicEmitter implements RepairStep {
+
+ /** @var IDBConnection */
+ protected $connection;
+
+ /**
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return 'Clean tags and favorites';
+ }
+
+ /**
+ * Updates the configuration after running an update
+ */
+ public function run() {
+ $this->deleteOrphanFileEntries();
+ $this->deleteOrphanTagEntries();
+ $this->deleteOrphanCategoryEntries();
+ }
+
+ /**
+ * Delete tag entries for deleted files
+ */
+ protected function deleteOrphanFileEntries() {
+ $this->deleteOrphanEntries(
+ '%d tags for delete files have been removed.',
+ 'vcategory_to_object', 'objid',
+ 'filecache', 'fileid', 'path_hash'
+ );
+ }
+
+ /**
+ * Delete tag entries for deleted tags
+ */
+ protected function deleteOrphanTagEntries() {
+ $this->deleteOrphanEntries(
+ '%d tag entries for deleted tags have been removed.',
+ 'vcategory_to_object', 'categoryid',
+ 'vcategory', 'id', 'uid'
+ );
+ }
+
+ /**
+ * Delete tags that have no entries
+ */
+ protected function deleteOrphanCategoryEntries() {
+ $this->deleteOrphanEntries(
+ '%d tags with no entries have been removed.',
+ 'vcategory', 'id',
+ 'vcategory_to_object', 'categoryid', 'type'
+ );
+ }
+
+ /**
+ * Deletes all entries from $deleteTable that do not have a matching entry in $sourceTable
+ *
+ * A query joins $deleteTable.$deleteId = $sourceTable.$sourceId and checks
+ * whether $sourceNullColumn is null. If it is null, the entry in $deleteTable
+ * is being deleted.
+ *
+ * @param string $repairInfo
+ * @param string $deleteTable
+ * @param string $deleteId
+ * @param string $sourceTable
+ * @param string $sourceId
+ * @param string $sourceNullColumn If this column is null in the source table,
+ * the entry is deleted in the $deleteTable
+ */
+ protected function deleteOrphanEntries($repairInfo, $deleteTable, $deleteId, $sourceTable, $sourceId, $sourceNullColumn) {
+ $qb = $this->connection->getQueryBuilder();
+
+ $qb->select('d.' . $deleteId)
+ ->from($deleteTable, 'd')
+ ->leftJoin('d', $sourceTable, 's', $qb->expr()->eq('d.' . $deleteId, ' s.' . $sourceId))
+ ->where(
+ $qb->expr()->eq('d.type', $qb->expr()->literal('files'))
+ )
+ ->andWhere(
+ $qb->expr()->isNull('s.' . $sourceNullColumn)
+ );
+ $result = $qb->execute();
+
+ $orphanItems = array();
+ while ($row = $result->fetch()) {
+ $orphanItems[] = (int) $row[$deleteId];
+ }
+
+ if (!empty($orphanItems)) {
+ $orphanItemsBatch = array_chunk($orphanItems, 200);
+ foreach ($orphanItemsBatch as $items) {
+ $qb->delete($deleteTable)
+ ->where(
+ $qb->expr()->eq('type', $qb->expr()->literal('files'))
+ )
+ ->andWhere($qb->expr()->in($deleteId, $qb->createParameter('ids')));
+ $qb->setParameter('ids', $items, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
+ $qb->execute();
+ }
+ }
+
+ if ($repairInfo) {
+ $this->emit('\OC\Repair', 'info', array(sprintf($repairInfo, sizeof($orphanItems))));
+ }
+ }
+}
diff --git a/lib/private/repair/collation.php b/lib/private/repair/collation.php
new file mode 100644
index 00000000000..7eb14f0ded2
--- /dev/null
+++ b/lib/private/repair/collation.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OC\Hooks\BasicEmitter;
+
+class Collation extends BasicEmitter implements \OC\RepairStep {
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var \OC\DB\Connection
+ */
+ protected $connection;
+
+ /**
+ * @param \OCP\IConfig $config
+ * @param \OC\DB\Connection $connection
+ */
+ public function __construct($config, $connection) {
+ $this->connection = $connection;
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Repair MySQL collation';
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+ if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
+ $this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to no'));
+ return;
+ }
+
+ $tables = $this->getAllNonUTF8BinTables($this->connection);
+ foreach ($tables as $table) {
+ $this->emit('\OC\Repair', 'info', array("Change collation for $table ..."));
+ $query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;');
+ $query->execute();
+ }
+ }
+
+ /**
+ * @param \Doctrine\DBAL\Connection $connection
+ * @return string[]
+ */
+ protected function getAllNonUTF8BinTables($connection) {
+ $dbName = $this->config->getSystemValue("dbname");
+ $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 TABLE_NAME LIKE \"*PREFIX*%\"",
+ array($dbName)
+ );
+ $result = array();
+ foreach ($rows as $row) {
+ $result[] = $row['table'];
+ }
+ return $result;
+ }
+}
+
diff --git a/lib/private/repair/dropoldjobs.php b/lib/private/repair/dropoldjobs.php
new file mode 100644
index 00000000000..89d7f96a144
--- /dev/null
+++ b/lib/private/repair/dropoldjobs.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * @author Arthur Schiwon <blizzz@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\BackgroundJob\IJobList;
+
+class DropOldJobs extends BasicEmitter implements RepairStep {
+
+ /** @var IJobList */
+ protected $jobList;
+
+ /**
+ * @param IJobList $jobList
+ */
+ public function __construct(IJobList $jobList) {
+ $this->jobList = $jobList;
+ }
+
+ /**
+ * Returns the step's name
+ *
+ * @return string
+ */
+ public function getName() {
+ return 'Drop old background jobs';
+ }
+
+ /**
+ * Run repair step.
+ * Must throw exception on error.
+ *
+ * @throws \Exception in case of failure
+ */
+ public function run() {
+ $oldJobs = $this->oldJobs();
+ foreach($oldJobs as $job) {
+ if($this->jobList->has($job['class'], $job['arguments'])) {
+ $this->jobList->remove($job['class'], $job['arguments']);
+ }
+ }
+ }
+
+ /**
+ * returns a list of old jobs as an associative array with keys 'class' and
+ * 'arguments'.
+ *
+ * @return array
+ */
+ public function oldJobs() {
+ return [
+ ['class' => 'OC_Cache_FileGlobalGC', 'arguments' => null],
+ ['class' => 'OC\Cache\FileGlobalGC', 'arguments' => null],
+ ];
+ }
+
+
+}
diff --git a/lib/private/repair/dropoldtables.php b/lib/private/repair/dropoldtables.php
new file mode 100644
index 00000000000..2d7fc8376b3
--- /dev/null
+++ b/lib/private/repair/dropoldtables.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IDBConnection;
+
+class DropOldTables extends BasicEmitter implements RepairStep {
+
+ /** @var IDBConnection */
+ protected $connection;
+
+ /**
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+ /**
+ * Returns the step's name
+ *
+ * @return string
+ */
+ public function getName() {
+ return 'Drop old database tables';
+ }
+
+ /**
+ * Run repair step.
+ * Must throw exception on error.
+ *
+ * @throws \Exception in case of failure
+ */
+ public function run() {
+ foreach ($this->oldDatabaseTables() as $tableName) {
+ if ($this->connection->tableExists($tableName)){
+ $this->emit('\OC\Repair', 'info', [
+ sprintf('Table %s has been deleted', $tableName)
+ ]);
+ $this->connection->dropTable($tableName);
+ }
+ }
+ }
+
+ /**
+ * Returns a list of outdated tables which are not used anymore
+ * @return array
+ */
+ protected function oldDatabaseTables() {
+ return [
+ 'calendar_calendars',
+ 'calendar_objects',
+ 'calendar_share_calendar',
+ 'calendar_share_event',
+ 'file_map',
+ 'foldersize',
+ 'fscache',
+ 'gallery_sharing',
+ 'locks',
+ 'log',
+ 'media_albums',
+ 'media_artists',
+ 'media_sessions',
+ 'media_songs',
+ 'media_users',
+ 'permissions',
+ 'pictures_images_cache',
+ 'principalgroups',
+ 'principals',
+ 'queuedtasks',
+ 'sharing',
+ ];
+ }
+}
diff --git a/lib/private/repair/filletags.php b/lib/private/repair/filletags.php
new file mode 100644
index 00000000000..8cfc4a7c258
--- /dev/null
+++ b/lib/private/repair/filletags.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+
+class FillETags extends BasicEmitter implements \OC\RepairStep {
+
+ /** @var \OCP\IDBConnection */
+ protected $connection;
+
+ /**
+ * @param \OCP\IDBConnection $connection
+ */
+ public function __construct($connection) {
+ $this->connection = $connection;
+ }
+
+ public function getName() {
+ return 'Generate ETags for file where no ETag is present.';
+ }
+
+ public function run() {
+ $qb = $this->connection->getQueryBuilder();
+ $qb->update('filecache')
+ ->set('etag', $qb->expr()->literal('xxx'))
+ ->where($qb->expr()->eq('etag', $qb->expr()->literal('')))
+ ->orWhere($qb->expr()->isNull('etag'));
+
+ $result = $qb->execute();
+ $this->emit('\OC\Repair', 'info', array("ETags have been fixed for $result files/folders."));
+ }
+}
+
diff --git a/lib/private/repair/innodb.php b/lib/private/repair/innodb.php
new file mode 100644
index 00000000000..4bbfdcea20a
--- /dev/null
+++ b/lib/private/repair/innodb.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <icewind@owncloud.com>
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use Doctrine\DBAL\Platforms\MySqlPlatform;
+use OC\Hooks\BasicEmitter;
+
+class InnoDB extends BasicEmitter implements \OC\RepairStep {
+
+ public function getName() {
+ return 'Repair MySQL database engine';
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+ $connection = \OC::$server->getDatabaseConnection();
+ if (!$connection->getDatabasePlatform() instanceof MySqlPlatform) {
+ $this->emit('\OC\Repair', 'info', array('Not a mysql database -> nothing to do'));
+ return;
+ }
+
+ $tables = $this->getAllMyIsamTables($connection);
+ if (is_array($tables)) {
+ foreach ($tables as $table) {
+ $connection->exec("ALTER TABLE $table ENGINE=InnoDB;");
+ $this->emit('\OC\Repair', 'info', array("Fixed $table"));
+ }
+ }
+ }
+
+ /**
+ * @param \Doctrine\DBAL\Connection $connection
+ * @return string[]
+ */
+ private function getAllMyIsamTables($connection) {
+ $dbName = \OC::$server->getConfig()->getSystemValue("dbname");
+ $result = $connection->fetchArray(
+ "SELECT table_name FROM information_schema.tables WHERE table_schema = ? AND engine = 'MyISAM' AND TABLE_NAME LIKE \"*PREFIX*%\"",
+ array($dbName)
+ );
+
+ return $result;
+ }
+}
+
diff --git a/lib/private/repair/oldgroupmembershipshares.php b/lib/private/repair/oldgroupmembershipshares.php
new file mode 100644
index 00000000000..2d701ac9fb7
--- /dev/null
+++ b/lib/private/repair/oldgroupmembershipshares.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IDBConnection;
+use OCP\IGroupManager;
+use OCP\Share;
+
+class OldGroupMembershipShares extends BasicEmitter implements RepairStep {
+
+ /** @var \OCP\IDBConnection */
+ protected $connection;
+
+ /** @var \OCP\IGroupManager */
+ protected $groupManager;
+
+ /**
+ * @var array [gid => [uid => (bool)]]
+ */
+ protected $memberships;
+
+ /**
+ * @param IDBConnection $connection
+ * @param IGroupManager $groupManager
+ */
+ public function __construct(IDBConnection $connection, IGroupManager $groupManager) {
+ $this->connection = $connection;
+ $this->groupManager = $groupManager;
+ }
+
+ /**
+ * Returns the step's name
+ *
+ * @return string
+ */
+ public function getName() {
+ return 'Remove shares of old group memberships';
+ }
+
+ /**
+ * Run repair step.
+ * Must throw exception on error.
+ *
+ * @throws \Exception in case of failure
+ */
+ public function run() {
+ $deletedEntries = 0;
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select(['s1.id', $query->createFunction('s1.`share_with` AS `user`'), $query->createFunction('s2.`share_with` AS `group`')])
+ ->from('share', 's1')
+ ->where($query->expr()->isNotNull('s1.parent'))
+ // \OC\Share\Constant::$shareTypeGroupUserUnique === 2
+ ->andWhere($query->expr()->eq('s1.share_type', $query->expr()->literal(2)))
+ ->andWhere($query->expr()->isNotNull('s2.id'))
+ ->andWhere($query->expr()->eq('s2.share_type', $query->expr()->literal(Share::SHARE_TYPE_GROUP)))
+ ->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'));
+
+ $deleteQuery = $this->connection->getQueryBuilder();
+ $deleteQuery->delete('share')
+ ->where($query->expr()->eq('id', $deleteQuery->createParameter('share')));
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ if (!$this->isMember($row['group'], $row['user'])) {
+ $deletedEntries += $deleteQuery->setParameter('share', (int) $row['id'])
+ ->execute();
+ }
+ }
+ $result->closeCursor();
+
+ if ($deletedEntries) {
+ $this->emit('\OC\Repair', 'info', array('Removed ' . $deletedEntries . ' shares where user is not a member of the group anymore'));
+ }
+ }
+
+ /**
+ * @param string $gid
+ * @param string $uid
+ * @return bool
+ */
+ protected function isMember($gid, $uid) {
+ if (isset($this->memberships[$gid][$uid])) {
+ return $this->memberships[$gid][$uid];
+ }
+
+ $isMember = $this->groupManager->isInGroup($uid, $gid);
+ if (!isset($this->memberships[$gid])) {
+ $this->memberships[$gid] = [];
+ }
+ $this->memberships[$gid][$uid] = $isMember;
+
+ return $isMember;
+ }
+}
diff --git a/lib/private/repair/preview.php b/lib/private/repair/preview.php
new file mode 100644
index 00000000000..2284da93734
--- /dev/null
+++ b/lib/private/repair/preview.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * @author Georg Ehrke <georg@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Files\View;
+use OC\Hooks\BasicEmitter;
+
+class Preview extends BasicEmitter implements \OC\RepairStep {
+
+ public function getName() {
+ return 'Cleaning-up broken previews';
+ }
+
+ public function run() {
+ $view = new View('/');
+ $children = $view->getDirectoryContent('/');
+
+ foreach ($children as $child) {
+ if ($view->is_dir($child->getPath())) {
+ $thumbnailsFolder = $child->getPath() . '/thumbnails';
+ if ($view->is_dir($thumbnailsFolder)) {
+ $view->rmdir($thumbnailsFolder);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/private/repair/removegetetagentries.php b/lib/private/repair/removegetetagentries.php
new file mode 100644
index 00000000000..40040763654
--- /dev/null
+++ b/lib/private/repair/removegetetagentries.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+use OCP\IDBConnection;
+
+class RemoveGetETagEntries extends BasicEmitter {
+
+ /**
+ * @var IDBConnection
+ */
+ protected $connection;
+
+ /**
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+ public function getName() {
+ return 'Remove getetag entries in properties table';
+ }
+
+ /**
+ * Removes all entries with the key "{DAV:}getetag" from the table properties
+ */
+ public function run() {
+ $sql = 'DELETE FROM `*PREFIX*properties`'
+ . ' WHERE `propertyname` = ?';
+ $deletedRows = $this->connection->executeUpdate($sql, ['{DAV:}getetag']);
+
+ $this->emit(
+ '\OC\Repair',
+ 'info',
+ ['Removed ' . $deletedRows . ' unneeded "{DAV:}getetag" entries from properties table.']
+ );
+ }
+}
diff --git a/lib/private/repair/repairinvalidshares.php b/lib/private/repair/repairinvalidshares.php
new file mode 100644
index 00000000000..5a4cb445ce9
--- /dev/null
+++ b/lib/private/repair/repairinvalidshares.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+
+/**
+ * Repairs shares with invalid data
+ */
+class RepairInvalidShares extends BasicEmitter implements \OC\RepairStep {
+
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var \OCP\IDBConnection
+ */
+ protected $connection;
+
+ /**
+ * @param \OCP\IConfig $config
+ * @param \OCP\IDBConnection $connection
+ */
+ public function __construct($config, $connection) {
+ $this->connection = $connection;
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Repair invalid shares';
+ }
+
+ /**
+ * Past bugs would make it possible to set an expiration date on user shares even
+ * though it is not supported. This functions removes the expiration date from such entries.
+ */
+ private function removeExpirationDateFromNonLinkShares() {
+ $builder = $this->connection->getQueryBuilder();
+ $builder
+ ->update('share')
+ ->set('expiration', 'null')
+ ->where($builder->expr()->isNotNull('expiration'))
+ ->andWhere($builder->expr()->neq('share_type', $builder->expr()->literal(\OC\Share\Constants::SHARE_TYPE_LINK)));
+
+ $updatedEntries = $builder->execute();
+ if ($updatedEntries > 0) {
+ $this->emit('\OC\Repair', 'info', array('Removed invalid expiration date from ' . $updatedEntries . ' shares'));
+ }
+ }
+
+ /**
+ * Remove shares where the parent share does not exist anymore
+ */
+ private function removeSharesNonExistingParent() {
+ $deletedEntries = 0;
+
+ $query = $this->connection->getQueryBuilder();
+ $query->select('s1.parent')
+ ->from('share', 's1')
+ ->where($query->expr()->isNotNull('s1.parent'))
+ ->andWhere($query->expr()->isNull('s2.id'))
+ ->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'))
+ ->groupBy('s1.parent');
+
+ $deleteQuery = $this->connection->getQueryBuilder();
+ $deleteQuery->delete('share')
+ ->where($query->expr()->eq('parent', $deleteQuery->createParameter('parent')));
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $deletedEntries += $deleteQuery->setParameter('parent', (int) $row['parent'])
+ ->execute();
+ }
+ $result->closeCursor();
+
+ if ($deletedEntries) {
+ $this->emit('\OC\Repair', 'info', array('Removed ' . $deletedEntries . ' shares where the parent did not exist'));
+ }
+ }
+
+ public function run() {
+ $ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
+ if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.7', '<')) {
+ // this situation was only possible before 8.2
+ $this->removeExpirationDateFromNonLinkShares();
+ }
+
+ $this->removeSharesNonExistingParent();
+ }
+}
diff --git a/lib/private/repair/repairlegacystorages.php b/lib/private/repair/repairlegacystorages.php
new file mode 100644
index 00000000000..5ba452cbbc6
--- /dev/null
+++ b/lib/private/repair/repairlegacystorages.php
@@ -0,0 +1,263 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Files\Cache\Storage;
+use OC\Hooks\BasicEmitter;
+use OC\RepairException;
+
+class RepairLegacyStorages extends BasicEmitter {
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var \OCP\IDBConnection
+ */
+ protected $connection;
+
+ protected $findStorageInCacheStatement;
+ protected $renameStorageStatement;
+
+ /**
+ * @param \OCP\IConfig $config
+ * @param \OCP\IDBConnection $connection
+ */
+ public function __construct($config, $connection) {
+ $this->connection = $connection;
+ $this->config = $config;
+
+ $this->findStorageInCacheStatement = $this->connection->prepare(
+ 'SELECT DISTINCT `storage` FROM `*PREFIX*filecache`'
+ . ' WHERE `storage` in (?, ?)'
+ );
+ $this->renameStorageStatement = $this->connection->prepare(
+ 'UPDATE `*PREFIX*storages`'
+ . ' SET `id` = ?'
+ . ' WHERE `id` = ?'
+ );
+ }
+
+ public function getName() {
+ return 'Repair legacy storages';
+ }
+
+ /**
+ * Extracts the user id from a legacy storage id
+ *
+ * @param string $storageId legacy storage id in the
+ * format "local::/path/to/datadir/userid"
+ * @return string user id extracted from the storage id
+ */
+ private function extractUserId($storageId) {
+ $storageId = rtrim($storageId, '/');
+ $pos = strrpos($storageId, '/');
+ return substr($storageId, $pos + 1);
+ }
+
+ /**
+ * Fix the given legacy storage by renaming the old id
+ * to the new id. If the new id already exists, whichever
+ * storage that has data in the file cache will be used.
+ * If both have data, nothing will be done and false is
+ * returned.
+ *
+ * @param string $oldId old storage id
+ * @param int $oldNumericId old storage numeric id
+ * @param string $userId
+ * @return bool true if fixed, false otherwise
+ * @throws RepairException
+ */
+ private function fixLegacyStorage($oldId, $oldNumericId, $userId = null) {
+ // check whether the new storage already exists
+ if (is_null($userId)) {
+ $userId = $this->extractUserId($oldId);
+ }
+ $newId = 'home::' . $userId;
+
+ // check if target id already exists
+ $newNumericId = Storage::getNumericStorageId($newId);
+ if (!is_null($newNumericId)) {
+ $newNumericId = (int)$newNumericId;
+ // try and resolve the conflict
+ // check which one of "local::" or "home::" needs to be kept
+ $this->findStorageInCacheStatement->execute(array($oldNumericId, $newNumericId));
+ $row1 = $this->findStorageInCacheStatement->fetch();
+ $row2 = $this->findStorageInCacheStatement->fetch();
+ $this->findStorageInCacheStatement->closeCursor();
+ if ($row2 !== false) {
+ // two results means both storages have data, not auto-fixable
+ throw new RepairException(
+ 'Could not automatically fix legacy storage '
+ . '"' . $oldId . '" => "' . $newId . '"'
+ . ' because they both have data.'
+ );
+ }
+ if ($row1 === false || (int)$row1['storage'] === $oldNumericId) {
+ // old storage has data, then delete the empty new id
+ $toDelete = $newId;
+ } else if ((int)$row1['storage'] === $newNumericId) {
+ // new storage has data, then delete the empty old id
+ $toDelete = $oldId;
+ } else {
+ // unknown case, do not continue
+ return false;
+ }
+
+ // delete storage including file cache
+ Storage::remove($toDelete);
+
+ // if we deleted the old id, the new id will be used
+ // automatically
+ if ($toDelete === $oldId) {
+ // nothing more to do
+ return true;
+ }
+ }
+
+ // rename old id to new id
+ $newId = Storage::adjustStorageId($newId);
+ $oldId = Storage::adjustStorageId($oldId);
+ $rowCount = $this->renameStorageStatement->execute(array($newId, $oldId));
+ $this->renameStorageStatement->closeCursor();
+ return ($rowCount === 1);
+ }
+
+ /**
+ * Converts legacy home storage ids in the format
+ * "local::/data/dir/path/userid/" to the new format "home::userid"
+ */
+ public function run() {
+ // only run once
+ if ($this->config->getAppValue('core', 'repairlegacystoragesdone') === 'yes') {
+ return;
+ }
+
+ $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/');
+ $dataDir = rtrim($dataDir, '/') . '/';
+ $dataDirId = 'local::' . $dataDir;
+
+ $count = 0;
+ $hasWarnings = false;
+
+ $this->connection->beginTransaction();
+
+ // note: not doing a direct UPDATE with the REPLACE function
+ // because regexp search/extract is needed and it is not guaranteed
+ // to work on all database types
+ $sql = 'SELECT `id`, `numeric_id` FROM `*PREFIX*storages`'
+ . ' WHERE `id` LIKE ?'
+ . ' ORDER BY `id`';
+ $result = $this->connection->executeQuery($sql, array($dataDirId . '%'));
+
+ while ($row = $result->fetch()) {
+ $currentId = $row['id'];
+ // one entry is the datadir itself
+ if ($currentId === $dataDirId) {
+ continue;
+ }
+
+ try {
+ if ($this->fixLegacyStorage($currentId, (int)$row['numeric_id'])) {
+ $count++;
+ }
+ }
+ catch (RepairException $e) {
+ $hasWarnings = true;
+ $this->emit(
+ '\OC\Repair',
+ 'warning',
+ array('Could not repair legacy storage ' . $currentId . ' automatically.')
+ );
+ }
+ }
+
+ // check for md5 ids, not in the format "prefix::"
+ $sql = 'SELECT COUNT(*) AS "c" FROM `*PREFIX*storages`'
+ . ' WHERE `id` NOT LIKE \'%::%\'';
+ $result = $this->connection->executeQuery($sql);
+ $row = $result->fetch();
+
+ // find at least one to make sure it's worth
+ // querying the user list
+ if ((int)$row['c'] > 0) {
+ $userManager = \OC::$server->getUserManager();
+
+ // use chunks to avoid caching too many users in memory
+ $limit = 30;
+ $offset = 0;
+
+ do {
+ // query the next page of users
+ $results = $userManager->search('', $limit, $offset);
+ $storageIds = array();
+ foreach ($results as $uid => $userObject) {
+ $storageId = $dataDirId . $uid . '/';
+ if (strlen($storageId) <= 64) {
+ // skip short storage ids as they were handled in the previous section
+ continue;
+ }
+ $storageIds[$uid] = $storageId;
+ }
+
+ if (count($storageIds) > 0) {
+ // update the storages of these users
+ foreach ($storageIds as $uid => $storageId) {
+ $numericId = Storage::getNumericStorageId($storageId);
+ try {
+ if (!is_null($numericId) && $this->fixLegacyStorage($storageId, (int)$numericId)) {
+ $count++;
+ }
+ }
+ catch (RepairException $e) {
+ $hasWarnings = true;
+ $this->emit(
+ '\OC\Repair',
+ 'warning',
+ array('Could not repair legacy storage ' . $storageId . ' automatically.')
+ );
+ }
+ }
+ }
+ $offset += $limit;
+ } while (count($results) >= $limit);
+ }
+
+ $this->emit('\OC\Repair', 'info', array('Updated ' . $count . ' legacy home storage ids'));
+
+ $this->connection->commit();
+
+ if ($hasWarnings) {
+ $this->emit(
+ '\OC\Repair',
+ 'warning',
+ array('Some legacy storages could not be repaired. Please manually fix them then re-run ./occ maintenance:repair')
+ );
+ } else {
+ // if all were done, no need to redo the repair during next upgrade
+ $this->config->setAppValue('core', 'repairlegacystoragesdone', 'yes');
+ }
+ }
+}
diff --git a/lib/private/repair/repairmimetypes.php b/lib/private/repair/repairmimetypes.php
new file mode 100644
index 00000000000..e687dbde688
--- /dev/null
+++ b/lib/private/repair/repairmimetypes.php
@@ -0,0 +1,360 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Normal Ra <normalraw@gmail.com>
+ * @author Olivier Paroz <github@oparoz.com>
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ * @author Victor Dubiniuk <dubiniuk@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+
+class RepairMimeTypes extends BasicEmitter implements \OC\RepairStep {
+ /**
+ * @var \OCP\IConfig
+ */
+ protected $config;
+
+ /**
+ * @var int
+ */
+ protected $folderMimeTypeId;
+
+ /**
+ * @param \OCP\IConfig $config
+ */
+ public function __construct($config) {
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Repair mime types';
+ }
+
+ private static function existsStmt() {
+ return \OC_DB::prepare('
+ SELECT count(`mimetype`)
+ FROM `*PREFIX*mimetypes`
+ WHERE `mimetype` = ?
+ ');
+ }
+
+ private static function getIdStmt() {
+ return \OC_DB::prepare('
+ SELECT `id`
+ FROM `*PREFIX*mimetypes`
+ WHERE `mimetype` = ?
+ ');
+ }
+
+ private static function insertStmt() {
+ return \OC_DB::prepare('
+ INSERT INTO `*PREFIX*mimetypes` ( `mimetype` )
+ VALUES ( ? )
+ ');
+ }
+
+ private static function updateWrongStmt() {
+ return \OC_DB::prepare('
+ UPDATE `*PREFIX*filecache`
+ SET `mimetype` = (
+ SELECT `id`
+ FROM `*PREFIX*mimetypes`
+ WHERE `mimetype` = ?
+ ) WHERE `mimetype` = ?
+ ');
+ }
+
+ private static function deleteStmt() {
+ return \OC_DB::prepare('
+ DELETE FROM `*PREFIX*mimetypes`
+ WHERE `id` = ?
+ ');
+ }
+
+ private static function updateByNameStmt() {
+ return \OC_DB::prepare('
+ UPDATE `*PREFIX*filecache`
+ SET `mimetype` = ?
+ WHERE `mimetype` <> ? AND `mimetype` <> ? AND `name` ILIKE ?
+ ');
+ }
+
+ private function repairMimetypes($wrongMimetypes) {
+ foreach ($wrongMimetypes as $wrong => $correct) {
+ // do we need to remove a wrong mimetype?
+ $result = \OC_DB::executeAudited(self::getIdStmt(), array($wrong));
+ $wrongId = $result->fetchOne();
+
+ if ($wrongId !== false) {
+ // do we need to insert the correct mimetype?
+ $result = \OC_DB::executeAudited(self::existsStmt(), array($correct));
+ $exists = $result->fetchOne();
+
+ if (!is_null($correct)) {
+ if (!$exists) {
+ // insert mimetype
+ \OC_DB::executeAudited(self::insertStmt(), array($correct));
+ }
+
+ // change wrong mimetype to correct mimetype in filecache
+ \OC_DB::executeAudited(self::updateWrongStmt(), array($correct, $wrongId));
+ }
+
+ // delete wrong mimetype
+ \OC_DB::executeAudited(self::deleteStmt(), array($wrongId));
+
+ }
+ }
+ }
+
+ private function updateMimetypes($updatedMimetypes) {
+ if (empty($this->folderMimeTypeId)) {
+ $result = \OC_DB::executeAudited(self::getIdStmt(), array('httpd/unix-directory'));
+ $this->folderMimeTypeId = (int)$result->fetchOne();
+ }
+
+ foreach ($updatedMimetypes as $extension => $mimetype) {
+ $result = \OC_DB::executeAudited(self::existsStmt(), array($mimetype));
+ $exists = $result->fetchOne();
+
+ if (!$exists) {
+ // insert mimetype
+ \OC_DB::executeAudited(self::insertStmt(), array($mimetype));
+ }
+
+ // get target mimetype id
+ $result = \OC_DB::executeAudited(self::getIdStmt(), array($mimetype));
+ $mimetypeId = $result->fetchOne();
+
+ // change mimetype for files with x extension
+ \OC_DB::executeAudited(self::updateByNameStmt(), array($mimetypeId, $this->folderMimeTypeId, $mimetypeId, '%.' . $extension));
+ }
+ }
+
+ private function fixOfficeMimeTypes() {
+ // update wrong mimetypes
+ $wrongMimetypes = array(
+ 'application/mspowerpoint' => 'application/vnd.ms-powerpoint',
+ 'application/msexcel' => 'application/vnd.ms-excel',
+ );
+
+ self::repairMimetypes($wrongMimetypes);
+
+ $updatedMimetypes = array(
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ );
+
+
+ // separate doc from docx etc
+ self::updateMimetypes($updatedMimetypes);
+
+ }
+
+ private function fixApkMimeType() {
+ $updatedMimetypes = array(
+ 'apk' => 'application/vnd.android.package-archive',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function fixFontsMimeTypes() {
+ // update wrong mimetypes
+ $wrongMimetypes = array(
+ 'font' => null,
+ 'font/opentype' => 'application/font-sfnt',
+ 'application/x-font-ttf' => 'application/font-sfnt',
+ );
+
+ self::repairMimetypes($wrongMimetypes);
+
+ $updatedMimetypes = array(
+ 'ttf' => 'application/font-sfnt',
+ 'otf' => 'application/font-sfnt',
+ 'pfb' => 'application/x-font',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function fixPostscriptMimeType() {
+ $updatedMimetypes = array(
+ 'eps' => 'application/postscript',
+ 'ps' => 'application/postscript',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceRawMimeType() {
+ $updatedMimetypes = array(
+ 'arw' => 'image/x-dcraw',
+ 'cr2' => 'image/x-dcraw',
+ 'dcr' => 'image/x-dcraw',
+ 'dng' => 'image/x-dcraw',
+ 'erf' => 'image/x-dcraw',
+ 'iiq' => 'image/x-dcraw',
+ 'k25' => 'image/x-dcraw',
+ 'kdc' => 'image/x-dcraw',
+ 'mef' => 'image/x-dcraw',
+ 'nef' => 'image/x-dcraw',
+ 'orf' => 'image/x-dcraw',
+ 'pef' => 'image/x-dcraw',
+ 'raf' => 'image/x-dcraw',
+ 'rw2' => 'image/x-dcraw',
+ 'srf' => 'image/x-dcraw',
+ 'sr2' => 'image/x-dcraw',
+ 'xrf' => 'image/x-dcraw',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduce3dImagesMimeType() {
+ $updatedMimetypes = array(
+ 'jps' => 'image/jpeg',
+ 'mpo' => 'image/jpeg',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceConfMimeType() {
+ $updatedMimetypes = array(
+ 'conf' => 'text/plain',
+ 'cnf' => 'text/plain',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceYamlMimeType() {
+ $updatedMimetypes = array(
+ 'yaml' => 'application/yaml',
+ 'yml' => 'application/yaml',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceJavaMimeType() {
+ $updatedMimetypes = array(
+ 'class' => 'application/java',
+ 'java' => 'text/x-java-source',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceHppMimeType() {
+ $updatedMimetypes = array(
+ 'hpp' => 'text/x-h',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceRssMimeType() {
+ $updatedMimetypes = array(
+ 'rss' => 'application/rss+xml',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceRtfMimeType() {
+ $updatedMimetypes = array(
+ 'rtf' => 'text/rtf',
+ );
+
+ self::updateMimetypes($updatedMimetypes);
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+
+ $ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
+
+ // NOTE TO DEVELOPERS: when adding new mime types, please make sure to
+ // add a version comparison to avoid doing it every time
+
+ // only update mime types if necessary as it can be expensive
+ if (version_compare($ocVersionFromBeforeUpdate, '8.2.0', '<')) {
+ if ($this->fixOfficeMimeTypes()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed office mime types'));
+ }
+
+ if ($this->fixApkMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed APK mime type'));
+ }
+
+ if ($this->fixFontsMimeTypes()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed fonts mime types'));
+ }
+
+ if ($this->fixPostscriptMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed Postscript mime types'));
+ }
+
+ if ($this->introduceRawMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed Raw mime types'));
+ }
+
+ if ($this->introduce3dImagesMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed 3D images mime types'));
+ }
+
+ if ($this->introduceConfMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed Conf/cnf mime types'));
+ }
+
+ if ($this->introduceYamlMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed Yaml/Yml mime types'));
+ }
+ }
+
+ // Mimetype updates from #19272
+ if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.8', '<')) {
+ if ($this->introduceJavaMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed java/class mime types'));
+ }
+
+ if ($this->introduceHppMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed hpp mime type'));
+ }
+
+ if ($this->introduceRssMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed rss mime type'));
+ }
+
+ if ($this->introduceRtfMimeType()) {
+ $this->emit('\OC\Repair', 'info', array('Fixed rtf mime type'));
+ }
+ }
+ }
+}
diff --git a/lib/private/repair/searchlucenetables.php b/lib/private/repair/searchlucenetables.php
new file mode 100644
index 00000000000..52d41083c45
--- /dev/null
+++ b/lib/private/repair/searchlucenetables.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+
+class SearchLuceneTables extends BasicEmitter implements \OC\RepairStep {
+
+ public function getName() {
+ return 'Repair duplicate entries in oc_lucene_status';
+ }
+
+ /**
+ * Fix duplicate entries in oc_lucene_status
+ *
+ * search_lucene prior to v0.5.0 did not have a primary key on the lucene_status table. Newer versions do, which
+ * causes the migration check to fail because it tries to insert duplicate rows into the new schema.
+ *
+ * FIXME Currently, apps don't have a way of repairing anything before the migration check:
+ * @link https://github.com/owncloud/core/issues/10980
+ *
+ * As a result this repair step needs to live in the core repo, although it belongs into search_lucene:
+ * @link https://github.com/owncloud/core/issues/10205#issuecomment-54957557
+ *
+ * It will completely remove any rows that make a file id have more than one status:
+ * fileid | status fileid | status
+ * --------+-------- will become --------+--------
+ * 2 | E 3 | E
+ * 2 | I
+ * 3 | E
+ *
+ * search_lucene will then reindex the fileids without a status when the next indexing job is executed
+ */
+ public function run() {
+ $connection = \OC::$server->getDatabaseConnection();
+ if ($connection->tableExists('lucene_status')) {
+ $this->emit('\OC\Repair', 'info', array('removing duplicate entries from lucene_status'));
+
+ $query = $connection->prepare('
+ DELETE FROM `*PREFIX*lucene_status`
+ WHERE `fileid` IN (
+ SELECT `fileid`
+ FROM (
+ SELECT `fileid`
+ FROM `*PREFIX*lucene_status`
+ GROUP BY `fileid`
+ HAVING count(`fileid`) > 1
+ ) AS `mysqlerr1093hack`
+ )');
+ $query->execute();
+ } else {
+ $this->emit('\OC\Repair', 'info', array('lucene_status table does not exist -> nothing to do'));
+ }
+ }
+
+}
+
diff --git a/lib/private/repair/sqliteautoincrement.php b/lib/private/repair/sqliteautoincrement.php
new file mode 100644
index 00000000000..70d0adae5d7
--- /dev/null
+++ b/lib/private/repair/sqliteautoincrement.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use Doctrine\DBAL\Platforms\SqlitePlatform;
+use Doctrine\DBAL\Schema\SchemaException;
+use Doctrine\DBAL\Schema\SchemaDiff;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Schema\ColumnDiff;
+use OC\Hooks\BasicEmitter;
+
+/**
+ * Fixes Sqlite autoincrement by forcing the SQLite table schemas to be
+ * altered in order to retrigger SQL schema generation through OCSqlitePlatform.
+ */
+class SqliteAutoincrement extends BasicEmitter implements \OC\RepairStep {
+ /**
+ * @var \OC\DB\Connection
+ */
+ protected $connection;
+
+ /**
+ * @param \OC\DB\Connection $connection
+ */
+ public function __construct($connection) {
+ $this->connection = $connection;
+ }
+
+ public function getName() {
+ return 'Repair SQLite autoincrement';
+ }
+
+ /**
+ * Fix mime types
+ */
+ public function run() {
+ if (!$this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
+ return;
+ }
+
+ $sourceSchema = $this->connection->getSchemaManager()->createSchema();
+
+ $schemaDiff = new SchemaDiff();
+
+ foreach ($sourceSchema->getTables() as $tableSchema) {
+ $primaryKey = $tableSchema->getPrimaryKey();
+ if (!$primaryKey) {
+ continue;
+ }
+
+ $columnNames = $primaryKey->getColumns();
+
+ // add a column diff for every primary key column,
+ // but do not actually change anything, this will
+ // force the generation of SQL statements to alter
+ // those tables, which will then trigger the
+ // specific SQL code from OCSqlitePlatform
+ try {
+ $tableDiff = new TableDiff($tableSchema->getName());
+ $tableDiff->fromTable = $tableSchema;
+ foreach ($columnNames as $columnName) {
+ $columnSchema = $tableSchema->getColumn($columnName);
+ $columnDiff = new ColumnDiff($columnSchema->getName(), $columnSchema);
+ $tableDiff->changedColumns[] = $columnDiff;
+ $schemaDiff->changedTables[] = $tableDiff;
+ }
+ } catch (SchemaException $e) {
+ // ignore
+ }
+ }
+
+ $this->connection->beginTransaction();
+ foreach ($schemaDiff->toSql($this->connection->getDatabasePlatform()) as $sql) {
+ $this->connection->query($sql);
+ }
+ $this->connection->commit();
+ }
+}
+
diff --git a/lib/private/repair/updatecertificatestore.php b/lib/private/repair/updatecertificatestore.php
new file mode 100644
index 00000000000..5fad309a959
--- /dev/null
+++ b/lib/private/repair/updatecertificatestore.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Files\View;
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OC\Server;
+use OCP\IConfig;
+
+/**
+ * Class UpdateCertificateStore rewrites the user specific certificate store after
+ * an update has been performed. This is done because a new root certificate file
+ * might have been added.
+ *
+ * @package OC\Repair
+ */
+class UpdateCertificateStore extends BasicEmitter implements RepairStep {
+ /**
+ * FIXME: The certificate manager does only allow specifying the user
+ * within the constructor. This makes DI impossible.
+ * @var Server
+ */
+ protected $server;
+ /** @var IConfig */
+ protected $config;
+
+ /**
+ * @param Server $server
+ * @param IConfig $config
+ */
+ public function __construct(Server $server,
+ IConfig $config) {
+ $this->server = $server;
+ $this->config = $config;
+ }
+
+ /** {@inheritDoc} */
+ public function getName() {
+ return 'Update user certificate stores with new root certificates';
+ }
+
+ /** {@inheritDoc} */
+ public function run() {
+ $rootView = new View();
+ $dataDirectory = $this->config->getSystemValue('datadirectory', null);
+ if(is_null($dataDirectory)) {
+ throw new \Exception('No data directory specified');
+ }
+
+ $pathToRootCerts = '/files_external/rootcerts.crt';
+
+ foreach($rootView->getDirectoryContent('', 'httpd/unix-directory') as $fileInfo) {
+ $uid = trim($fileInfo->getPath(), '/');
+ if($rootView->file_exists($uid . $pathToRootCerts)) {
+ // Delete the existing root certificate
+ $rootView->unlink($uid . $pathToRootCerts);
+
+ /**
+ * FIXME: The certificate manager does only allow specifying the user
+ * within the constructor. This makes DI impossible.
+ */
+ // Regenerate the certificates
+ $certificateManager = $this->server->getCertificateManager($uid);
+ $certificateManager->createCertificateBundle();
+ }
+ }
+ }
+}
diff --git a/lib/private/repair/updateoutdatedocsids.php b/lib/private/repair/updateoutdatedocsids.php
new file mode 100644
index 00000000000..5f6ee029536
--- /dev/null
+++ b/lib/private/repair/updateoutdatedocsids.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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\Repair;
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IConfig;
+
+/**
+ * Class UpdateOutdatedOcsIds is used to update invalid outdated OCS IDs, this is
+ * for example the case when an application has had another OCS ID in the past such
+ * as for contacts and calendar when apps.owncloud.com migrated to a unified identifier
+ * for multiple versions.
+ *
+ * @package OC\Repair
+ */
+class UpdateOutdatedOcsIds extends BasicEmitter implements RepairStep {
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * @param IConfig $config
+ */
+ public function __construct(IConfig $config) {
+ $this->config = $config;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName() {
+ return 'Repair outdated OCS IDs';
+ }
+
+ /**
+ * @param string $appName
+ * @param string $oldId
+ * @param string $newId
+ * @return bool True if updated, false otherwise
+ */
+ public function fixOcsId($appName, $oldId, $newId) {
+ $existingId = $this->config->getAppValue($appName, 'ocsid');
+
+ if($existingId === $oldId) {
+ $this->config->setAppValue($appName, 'ocsid', $newId);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run() {
+ $appsToUpdate = [
+ 'contacts' => [
+ 'old' => '166044',
+ 'new' => '168708',
+ ],
+ 'calendar' => [
+ 'old' => '166043',
+ 'new' => '168707',
+ ],
+ 'bookmarks' => [
+ 'old' => '166042',
+ 'new' => '168710',
+ ],
+ 'search_lucene' => [
+ 'old' => '166057',
+ 'new' => '168709',
+ ],
+ 'documents' => [
+ 'old' => '166045',
+ 'new' => '168711',
+ ]
+ ];
+
+ foreach($appsToUpdate as $appName => $ids) {
+ if ($this->fixOcsId($appName, $ids['old'], $ids['new'])) {
+ $this->emit(
+ '\OC\Repair',
+ 'info',
+ [sprintf('Fixed invalid %s OCS id', $appName)]
+ );
+ }
+ }
+ }
+}
diff --git a/lib/private/route/router.php b/lib/private/route/router.php
index 4ca5e16ddf2..5cfddca966a 100644
--- a/lib/private/route/router.php
+++ b/lib/private/route/router.php
@@ -33,6 +33,7 @@ namespace OC\Route;
use OCP\ILogger;
use OCP\Route\IRouter;
use OCP\AppFramework\App;
+use OCP\Util;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\Generator\UrlGenerator;
@@ -41,49 +42,26 @@ use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
class Router implements IRouter {
- /**
- * @var \Symfony\Component\Routing\RouteCollection[]
- */
- protected $collections = array();
-
- /**
- * @var \Symfony\Component\Routing\RouteCollection
- */
+ /** @var RouteCollection[] */
+ protected $collections = [];
+ /** @var null|RouteCollection */
protected $collection = null;
-
- /**
- * @var string
- */
+ /** @var null|string */
protected $collectionName = null;
-
- /**
- * @var \Symfony\Component\Routing\RouteCollection
- */
+ /** @var null|RouteCollection */
protected $root = null;
-
- /**
- * @var \Symfony\Component\Routing\Generator\UrlGenerator
- */
+ /** @var null|UrlGenerator */
protected $generator = null;
-
- /**
- * @var string[]
- */
+ /** @var string[] */
protected $routingFiles;
-
- /**
- * @var string
- */
- protected $cacheKey;
-
+ /** @var bool */
protected $loaded = false;
-
- protected $loadedApps = array();
-
- /**
- * @var ILogger
- */
+ /** @var array */
+ protected $loadedApps = [];
+ /** @var ILogger */
protected $logger;
+ /** @var RequestContext */
+ protected $context;
/**
* @param ILogger $logger
@@ -92,7 +70,7 @@ class Router implements IRouter {
$this->logger = $logger;
$baseUrl = \OC::$WEBROOT;
if(!(getenv('front_controller_active') === 'true')) {
- $baseUrl = \OC_Helper::linkTo('', 'index.php');
+ $baseUrl = \OC::$server->getURLGenerator()->linkTo('', 'index.php');
}
if (!\OC::$CLI) {
$method = $_SERVER['REQUEST_METHOD'];
@@ -114,7 +92,7 @@ class Router implements IRouter {
*/
public function getRoutingFiles() {
if (!isset($this->routingFiles)) {
- $this->routingFiles = array();
+ $this->routingFiles = [];
foreach (\OC_APP::getEnabledApps() as $app) {
$file = \OC_App::getAppPath($app) . '/appinfo/routes.php';
if (file_exists($file)) {
@@ -126,23 +104,9 @@ class Router implements IRouter {
}
/**
- * @return string
- */
- public function getCacheKey() {
- if (!isset($this->cacheKey)) {
- $files = $this->getRoutingFiles();
- $files[] = 'settings/routes.php';
- $files[] = 'core/routes.php';
- $files[] = 'ocs/routes.php';
- $this->cacheKey = \OC\Cache::generateCacheKeyFromFiles($files);
- }
- return $this->cacheKey;
- }
-
- /**
- * loads the api routes
+ * Loads the routes
*
- * @return void
+ * @param null|string $app
*/
public function loadRoutes($app = null) {
$requestedApp = $app;
@@ -157,10 +121,10 @@ class Router implements IRouter {
return;
}
$file = \OC_App::getAppPath($app) . '/appinfo/routes.php';
- if (file_exists($file)) {
- $routingFiles = array($app => $file);
+ if ($file !== false && file_exists($file)) {
+ $routingFiles = [$app => $file];
} else {
- $routingFiles = array();
+ $routingFiles = [];
}
}
\OC::$server->getEventLogger()->start('loadroutes' . $requestedApp, 'Loading Routes');
@@ -183,12 +147,12 @@ class Router implements IRouter {
if (!isset($this->loadedApps['core'])) {
$this->loadedApps['core'] = true;
$this->useCollection('root');
- require_once 'settings/routes.php';
- require_once 'core/routes.php';
+ require_once __DIR__ . '/../../../settings/routes.php';
+ require_once __DIR__ . '/../../../core/routes.php';
}
if ($this->loaded) {
// include ocs routes, must be loaded last for /ocs prefix
- require_once 'ocs/routes.php';
+ require_once __DIR__ . '/../../../ocs/routes.php';
$collection = $this->getCollection('ocs');
$collection->addPrefix('/ocs');
$this->root->addCollection($collection);
@@ -197,6 +161,14 @@ class Router implements IRouter {
}
/**
+ * @return string
+ * @deprecated
+ */
+ public function getCacheKey() {
+ return '';
+ }
+
+ /**
* @param string $name
* @return \Symfony\Component\Routing\RouteCollection
*/
@@ -237,7 +209,10 @@ class Router implements IRouter {
* @param array $requirements An array of requirements for parameters (regexes)
* @return \OC\Route\Route
*/
- public function create($name, $pattern, array $defaults = array(), array $requirements = array()) {
+ public function create($name,
+ $pattern,
+ array $defaults = [],
+ array $requirements = []) {
$route = new Route($pattern, $defaults, $requirements);
$this->collection->add($name, $route);
return $route;
@@ -260,7 +235,7 @@ class Router implements IRouter {
$this->loadRoutes($app);
} else if (substr($url, 0, 6) === '/core/' or substr($url, 0, 10) === '/settings/') {
\OC::$REQUESTEDAPP = $url;
- if (!\OC::$server->getConfig()->getSystemValue('maintenance', false) && !\OCP\Util::needUpgrade()) {
+ if (!\OC::$server->getConfig()->getSystemValue('maintenance', false) && !Util::needUpgrade()) {
\OC_App::loadApps();
}
$this->loadRoutes('core');
@@ -325,10 +300,16 @@ class Router implements IRouter {
* @param bool $absolute
* @return string
*/
- public function generate($name, $parameters = array(), $absolute = false) {
+ public function generate($name,
+ $parameters = [],
+ $absolute = false) {
$this->loadRoutes();
try {
- return $this->getGenerator()->generate($name, $parameters, $absolute);
+ $referenceType = UrlGenerator::ABSOLUTE_URL;
+ if ($absolute === false) {
+ $referenceType = UrlGenerator::ABSOLUTE_PATH;
+ }
+ return $this->getGenerator()->generate($name, $parameters, $referenceType);
} catch (RouteNotFoundException $e) {
$this->logger->logException($e);
return '';
@@ -372,6 +353,4 @@ class Router implements IRouter {
$application->registerRoutes($this, $routes);
}
}
-
-
}
diff --git a/lib/private/security/crypto.php b/lib/private/security/crypto.php
index 0bd34df3f36..46d0c750b2f 100644
--- a/lib/private/security/crypto.php
+++ b/lib/private/security/crypto.php
@@ -123,7 +123,7 @@ class Crypto implements ICrypto {
$this->cipher->setIV($iv);
- if(!\OCP\Security\StringUtils::equals($this->calculateHMAC($parts[0].$parts[1], $password), $hmac)) {
+ if(!hash_equals($this->calculateHMAC($parts[0].$parts[1], $password), $hmac)) {
throw new \Exception('HMAC does not match.');
}
diff --git a/lib/private/security/hasher.php b/lib/private/security/hasher.php
index a5dd22e5dc8..318141b6852 100644
--- a/lib/private/security/hasher.php
+++ b/lib/private/security/hasher.php
@@ -109,7 +109,7 @@ class Hasher implements IHasher {
// Verify whether it matches a legacy PHPass or SHA1 string
$hashLength = strlen($hash);
if($hashLength === 60 && password_verify($message.$this->legacySalt, $hash) ||
- $hashLength === 40 && StringUtils::equals($hash, sha1($message))) {
+ $hashLength === 40 && hash_equals($hash, sha1($message))) {
$newHash = $this->hash($message);
return true;
}
diff --git a/lib/private/security/securerandom.php b/lib/private/security/securerandom.php
index 87dca68985e..24affbe8988 100644
--- a/lib/private/security/securerandom.php
+++ b/lib/private/security/securerandom.php
@@ -27,25 +27,15 @@ use Sabre\DAV\Exception;
use OCP\Security\ISecureRandom;
/**
- * Class SecureRandom provides a layer around RandomLib to generate
- * secure random strings. For PHP 7 the native CSPRNG is used.
+ * Class SecureRandom provides a wrapper around the random_int function to generate
+ * secure random strings. For PHP 7 the native CSPRNG is used, older versions do
+ * use a fallback.
*
* Usage:
- * \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(10);
- *
+ * \OC::$server->getSecureRandom()->generate(10);
* @package OC\Security
*/
class SecureRandom implements ISecureRandom {
-
- /** @var \RandomLib\Factory */
- var $factory;
- /** @var \RandomLib\Generator */
- var $generator;
-
- function __construct() {
- $this->factory = new RandomLib\Factory;
- }
-
/**
* Convenience method to get a low strength random number generator.
*
@@ -53,10 +43,10 @@ class SecureRandom implements ISecureRandom {
* in a non-cryptographical setting. They are not strong enough to be
* used as keys or salts. They are however useful for one-time use tokens.
*
+ * @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int()
* @return $this
*/
public function getLowStrengthGenerator() {
- $this->generator = $this->factory->getLowStrengthGenerator();
return $this;
}
@@ -67,10 +57,10 @@ class SecureRandom implements ISecureRandom {
* They are strong enough to be used as keys and salts. However, they do
* take some time and resources to generate, so they should not be over-used
*
+ * @deprecated 9.0.0 Use \OC\Security\SecureRandom::generate directly or random_bytes() / random_int()
* @return $this
*/
public function getMediumStrengthGenerator() {
- $this->generator = $this->factory->getMediumStrengthGenerator();
return $this;
}
@@ -80,26 +70,17 @@ class SecureRandom implements ISecureRandom {
* @param string $characters An optional list of characters to use if no character list is
* specified all valid base64 characters are used.
* @return string
- * @throws \Exception If the generator is not initialized.
*/
public function generate($length,
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') {
- if(is_null($this->generator)) {
- throw new \Exception('Generator is not initialized.');
- }
+ $maxCharIndex = strlen($characters) - 1;
+ $randomString = '';
- if(function_exists('random_int')) {
- $maxCharIndex = strlen($characters) - 1;
- $randomString = '';
-
- while($length > 0) {
- $randomNumber = random_int(0, $maxCharIndex);
- $randomString .= $characters[$randomNumber];
- $length--;
- }
- return $randomString;
+ while($length > 0) {
+ $randomNumber = random_int(0, $maxCharIndex);
+ $randomString .= $characters[$randomNumber];
+ $length--;
}
-
- return $this->generator->generateString($length, $characters);
+ return $randomString;
}
}
diff --git a/lib/private/security/stringutils.php b/lib/private/security/stringutils.php
deleted file mode 100644
index fa4342a2b45..00000000000
--- a/lib/private/security/stringutils.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @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\Security;
-
-class StringUtils {
-
- /**
- * Compares whether two strings are equal. To prevent guessing of the string
- * length this is done by comparing two hashes against each other and afterwards
- * a comparison of the real string to prevent against the unlikely chance of
- * collisions.
- *
- * Be aware that this function may leak whether the string to compare have a different
- * length.
- *
- * @param string $expected The expected value
- * @param string $input The input to compare against
- * @return bool True if the two strings are equal, otherwise false.
- */
- public static function equals($expected, $input) {
-
- if(!is_string($expected) || !is_string($input)) {
- return false;
- }
-
- if(function_exists('hash_equals')) {
- return hash_equals($expected, $input);
- }
-
- $randomString = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(10);
-
- if(hash('sha512', $expected.$randomString) === hash('sha512', $input.$randomString)) {
- if($expected === $input) {
- return true;
- }
- }
-
- return false;
- }
-} \ No newline at end of file
diff --git a/lib/private/server.php b/lib/private/server.php
index 8439500706d..a21ff58f355 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -78,14 +78,15 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
*
* TODO: hookup all manager classes
*/
-class Server extends SimpleContainer implements IServerContainer {
+class Server extends ServerContainer implements IServerContainer {
/** @var string */
private $webRoot;
/**
* @param string $webRoot
+ * @param \OC\Config $config
*/
- public function __construct($webRoot) {
+ public function __construct($webRoot, \OC\Config $config) {
parent::__construct();
$this->webRoot = $webRoot;
@@ -238,11 +239,11 @@ class Server extends SimpleContainer implements IServerContainer {
$c->getSystemConfig()
);
});
- $this->registerService('SystemConfig', function ($c) {
- return new \OC\SystemConfig();
+ $this->registerService('SystemConfig', function ($c) use ($config) {
+ return new \OC\SystemConfig($config);
});
- $this->registerService('AppConfig', function ($c) {
- return new \OC\AppConfig(\OC_DB::getConnection());
+ $this->registerService('AppConfig', function (Server $c) {
+ return new \OC\AppConfig($c->getDatabaseConnection());
});
$this->registerService('L10NFactory', function ($c) {
return new \OC\L10N\Factory();
diff --git a/lib/private/servercontainer.php b/lib/private/servercontainer.php
new file mode 100644
index 00000000000..385700957a1
--- /dev/null
+++ b/lib/private/servercontainer.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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;
+
+
+use OC\AppFramework\DependencyInjection\DIContainer;
+use OC\AppFramework\Utility\SimpleContainer;
+use OCP\AppFramework\QueryException;
+
+/**
+ * Class ServerContainer
+ *
+ * @package OC
+ */
+class ServerContainer extends SimpleContainer {
+ /** @var DIContainer[] */
+ protected $appContainers;
+
+ /**
+ * ServerContainer constructor.
+ */
+ public function __construct() {
+ parent::__construct();
+ $this->appContainers = [];
+ }
+
+ /**
+ * @param string $appName
+ * @param DIContainer $container
+ */
+ public function registerAppContainer($appName, DIContainer $container) {
+ $this->appContainers[$appName] = $container;
+ }
+
+ /**
+ * @param string $appName
+ * @return DIContainer
+ */
+ public function getAppContainer($appName) {
+ if (isset($this->appContainers[$appName])) {
+ return $this->appContainers[$appName];
+ }
+
+ return new DIContainer($appName);
+ }
+
+ /**
+ * @param string $name name of the service to query for
+ * @return mixed registered service for the given $name
+ * @throws QueryException if the query could not be resolved
+ */
+ public function query($name) {
+ $name = $this->sanitizeName($name);
+
+ // In case the service starts with OCA\ we try to find the service in
+ // the apps container first.
+ if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
+ $segments = explode('\\', $name);
+ $appContainer = $this->getAppContainer(strtolower($segments[1]));
+ try {
+ return $appContainer->query($name);
+ } catch (QueryException $e) {
+ // Didn't find the service in the respective app container,
+ // ignore it and fall back to the core container.
+ }
+ }
+
+ return parent::query($name);
+ }
+}
diff --git a/lib/private/session/cryptosessiondata.php b/lib/private/session/cryptosessiondata.php
index dcae1648fe1..b600874412b 100644
--- a/lib/private/session/cryptosessiondata.php
+++ b/lib/private/session/cryptosessiondata.php
@@ -132,6 +132,16 @@ class CryptoSessionData implements \ArrayAccess, ISession {
}
/**
+ * Wrapper around session_regenerate_id
+ *
+ * @param bool $deleteOldSession Whether to delete the old associated session file or not.
+ * @return void
+ */
+ public function regenerateId($deleteOldSession = true) {
+ $this->session->regenerateId($deleteOldSession);
+ }
+
+ /**
* Close the session and release the lock, also writes all changed data in batch
*/
public function close() {
diff --git a/lib/private/session/internal.php b/lib/private/session/internal.php
index 0b6152acf12..8be3356c6db 100644
--- a/lib/private/session/internal.php
+++ b/lib/private/session/internal.php
@@ -89,10 +89,9 @@ class Internal extends Session {
}
}
-
public function clear() {
session_unset();
- @session_regenerate_id(true);
+ $this->regenerateId();
@session_start();
$_SESSION = array();
}
@@ -102,14 +101,35 @@ class Internal extends Session {
parent::close();
}
- public function reopen() {
- throw new \Exception('The session cannot be reopened - reopen() is ony to be used in unit testing.');
- }
+ /**
+ * Wrapper around session_regenerate_id
+ *
+ * @param bool $deleteOldSession Whether to delete the old associated session file or not.
+ * @return void
+ */
+ public function regenerateId($deleteOldSession = true) {
+ @session_regenerate_id($deleteOldSession);
+ }
+
+ /**
+ * @throws \Exception
+ */
+ public function reopen() {
+ throw new \Exception('The session cannot be reopened - reopen() is ony to be used in unit testing.');
+ }
+ /**
+ * @param int $errorNumber
+ * @param string $errorString
+ * @throws \ErrorException
+ */
public function trapError($errorNumber, $errorString) {
throw new \ErrorException($errorString);
}
+ /**
+ * @throws \Exception
+ */
private function validateSession() {
if ($this->sessionClosed) {
throw new \Exception('Session has been closed - no further changes to the session are allowed');
diff --git a/lib/private/session/memory.php b/lib/private/session/memory.php
index ff95efc5345..c6090087457 100644
--- a/lib/private/session/memory.php
+++ b/lib/private/session/memory.php
@@ -81,6 +81,13 @@ class Memory extends Session {
}
/**
+ * Stub since the session ID does not need to get regenerated for the cache
+ *
+ * @param bool $deleteOldSession
+ */
+ public function regenerateId($deleteOldSession = true) {}
+
+ /**
* Helper function for PHPUnit execution - don't use in non-test code
*/
public function reopen() {
diff --git a/lib/private/setup.php b/lib/private/setup.php
index 814d78679e2..770f5cdab52 100644
--- a/lib/private/setup.php
+++ b/lib/private/setup.php
@@ -322,7 +322,7 @@ class Setup {
'datadirectory' => $dataDir,
'overwrite.cli.url' => $request->getServerProtocol() . '://' . $request->getInsecureServerHost() . \OC::$WEBROOT,
'dbtype' => $dbType,
- 'version' => implode('.', \OC_Util::getVersion()),
+ 'version' => implode('.', \OCP\Util::getVersion()),
]);
try {
@@ -369,11 +369,9 @@ class Setup {
// out that this is indeed an ownCloud data directory
file_put_contents($config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', '');
- // Update htaccess files for apache hosts
- if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
- self::updateHtaccess();
- self::protectDataDirectory();
- }
+ // Update .htaccess files
+ Setup::updateHtaccess();
+ Setup::protectDataDirectory();
//try to write logtimezone
if (date_default_timezone_get()) {
@@ -395,32 +393,17 @@ class Setup {
}
/**
- * Checks if the .htaccess contains the current version parameter
- *
- * @return bool
- */
- private function isCurrentHtaccess() {
- $version = \OC_Util::getVersion();
- unset($version[3]);
-
- return !strpos(
- file_get_contents($this->pathToHtaccess()),
- 'Version: '.implode('.', $version)
- ) === false;
- }
-
- /**
* Append the correct ErrorDocument path for Apache hosts
- *
- * @throws \OC\HintException If .htaccess does not include the current version
*/
public static function updateHtaccess() {
+ // From CLI we don't know the defined web root. Thus we can't write any
+ // directives into the .htaccess file.
+ if(\OC::$CLI) {
+ return;
+ }
$setupHelper = new \OC\Setup(\OC::$server->getConfig(), \OC::$server->getIniWrapper(),
\OC::$server->getL10N('lib'), new \OC_Defaults(), \OC::$server->getLogger(),
\OC::$server->getSecureRandom());
- if(!$setupHelper->isCurrentHtaccess()) {
- throw new \OC\HintException('.htaccess file has the wrong version. Please upload the correct version. Maybe you forgot to replace it after updating?');
- }
$htaccessContent = file_get_contents($setupHelper->pathToHtaccess());
$content = '';
@@ -439,6 +422,9 @@ class Setup {
$content.="\n RewriteBase ".$webRoot;
$content .= "\n <IfModule mod_env.c>";
$content .= "\n SetEnv front_controller_active true";
+ $content .= "\n <IfModule mod_dir.c>";
+ $content .= "\n DirectorySlash off";
+ $content .= "\n </IfModule>";
$content.="\n </IfModule>";
$content.="\n</IfModule>";
diff --git a/lib/private/share/helper.php b/lib/private/share/helper.php
index 26bbca81317..0441647df83 100644
--- a/lib/private/share/helper.php
+++ b/lib/private/share/helper.php
@@ -289,4 +289,38 @@ class Helper extends \OC\Share\Constants {
$hint = $l->t('Invalid Federated Cloud ID');
throw new HintException('Invalid Fededrated Cloud ID', $hint);
}
+
+ /**
+ * check if two federated cloud IDs refer to the same user
+ *
+ * @param string $user1
+ * @param string $server1
+ * @param string $user2
+ * @param string $server2
+ * @return bool true if both users and servers are the same
+ */
+ public static function isSameUserOnSameServer($user1, $server1, $user2, $server2) {
+ $normalizedServer1 = strtolower(\OC\Share\Share::removeProtocolFromUrl($server1));
+ $normalizedServer2 = strtolower(\OC\Share\Share::removeProtocolFromUrl($server2));
+
+ if (rtrim($normalizedServer1, '/') === rtrim($normalizedServer2, '/')) {
+ // FIXME this should be a method in the user management instead
+ \OCP\Util::emitHook(
+ '\OCA\Files_Sharing\API\Server2Server',
+ 'preLoginNameUsedAsUserName',
+ array('uid' => &$user1)
+ );
+ \OCP\Util::emitHook(
+ '\OCA\Files_Sharing\API\Server2Server',
+ 'preLoginNameUsedAsUserName',
+ array('uid' => &$user2)
+ );
+
+ if ($user1 === $user2) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/lib/private/share/mailnotifications.php b/lib/private/share/mailnotifications.php
index 4d282158ba4..f071c7f3a3c 100644
--- a/lib/private/share/mailnotifications.php
+++ b/lib/private/share/mailnotifications.php
@@ -170,7 +170,7 @@ class MailNotifications {
* @param string $filename the shared file
* @param string $link the public link
* @param int $expiration expiration date (timestamp)
- * @return array $result of failed recipients
+ * @return string[] $result of failed recipients
*/
public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
$subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
@@ -232,8 +232,8 @@ class MailNotifications {
}
/**
- * @param $itemSource
- * @param $itemType
+ * @param string $itemSource
+ * @param string $itemType
* @param IUser $recipient
* @return array
*/
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index 3edffba8a3f..db27fa6a891 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -436,7 +436,7 @@ class Share extends Constants {
// TODO: inject connection, hopefully one day in the future when this
// class isn't static anymore...
- $conn = \OC_DB::getConnection();
+ $conn = \OC::$server->getDatabaseConnection();
$result = $conn->executeQuery(
'SELECT ' . $select . ' FROM `*PREFIX*share` ' . $where,
$arguments,
@@ -491,7 +491,7 @@ class Share extends Constants {
public static function getShareByToken($token, $checkPasswordProtection = true) {
$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?', 1);
$result = $query->execute(array($token));
- if (\OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage() . ', token=' . $token, \OCP\Util::ERROR);
}
$row = $result->fetchRow();
@@ -849,11 +849,20 @@ class Share extends Constants {
throw new \Exception($message_t);
}
+ // don't allow federated shares if source and target server are the same
+ list($user, $remote) = Helper::splitUserRemote($shareWith);
+ $currentServer = self::removeProtocolFromUrl(\OC::$server->getURLGenerator()->getAbsoluteURL('/'));
+ $currentUser = \OC::$server->getUserSession()->getUser()->getUID();
+ if (Helper::isSameUserOnSameServer($user, $remote, $currentUser, $currentServer)) {
+ $message = 'Not allowed to create a federated share with the same user.';
+ $message_t = $l->t('Not allowed to create a federated share with the same user');
+ \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::DEBUG);
+ throw new \Exception($message_t);
+ }
$token = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
\OCP\Security\ISecureRandom::CHAR_DIGITS);
- list($user, $remote) = Helper::splitUserRemote($shareWith);
$shareWith = $user . '@' . $remote;
$shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
@@ -1713,7 +1722,7 @@ class Share extends Constants {
$root = strlen($root);
$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
$result = $query->execute($queryArgs);
- if (\OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('OCP\Share',
\OC_DB::getErrorMessage() . ', select=' . $select . ' where=',
\OCP\Util::ERROR);
@@ -1777,7 +1786,7 @@ class Share extends Constants {
if (isset($row['parent'])) {
$query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
$parentResult = $query->execute(array($row['parent']));
- if (\OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
\OCP\Util::ERROR);
@@ -2182,7 +2191,7 @@ class Share extends Constants {
if ($isGroupShare) {
$id = self::insertShare($queriesToExecute['groupShare']);
// Save this id, any extra rows for this group share will need to reference it
- $parent = \OC_DB::insertid('*PREFIX*share');
+ $parent = \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*share');
unset($queriesToExecute['groupShare']);
}
@@ -2510,7 +2519,7 @@ class Share extends Constants {
* @param string $url
* @return string
*/
- private static function removeProtocolFromUrl($url) {
+ public static function removeProtocolFromUrl($url) {
if (strpos($url, 'https://') === 0) {
return substr($url, strlen('https://'));
} else if (strpos($url, 'http://') === 0) {
diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php
index bc3bc0ce9ed..a7155644920 100644
--- a/lib/private/share20/defaultshareprovider.php
+++ b/lib/private/share20/defaultshareprovider.php
@@ -64,11 +64,90 @@ class DefaultShareProvider implements IShareProvider {
/**
* Share a path
- *
+ *
* @param IShare $share
* @return IShare The share object
+ * @throws ShareNotFound
+ * @throws \Exception
*/
public function create(IShare $share) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->insert('share');
+ $qb->setValue('share_type', $qb->createNamedParameter($share->getShareType()));
+
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ //Set the UID of the user we share with
+ $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()->getUID()));
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ //Set the GID of the group we share with
+ $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()->getGID()));
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ //Set the token of the share
+ $qb->setValue('token', $qb->createNamedParameter($share->getToken()));
+
+ //If a password is set store it
+ if ($share->getPassword() !== null) {
+ $qb->setValue('share_with', $qb->createNamedParameter($share->getPassword()));
+ }
+
+ //If an expiration date is set store it
+ if ($share->getExpirationDate() !== null) {
+ $qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime'));
+ }
+ } else {
+ throw new \Exception('invalid share type!');
+ }
+
+ // Set what is shares
+ $qb->setValue('item_type', $qb->createParameter('itemType'));
+ if ($share->getPath() instanceof \OCP\Files\File) {
+ $qb->setParameter('itemType', 'file');
+ } else {
+ $qb->setParameter('itemType', 'folder');
+ }
+
+ // Set the file id
+ $qb->setValue('item_source', $qb->createNamedParameter($share->getPath()->getId()));
+ $qb->setValue('file_source', $qb->createNamedParameter($share->getPath()->getId()));
+
+ // set the permissions
+ $qb->setValue('permissions', $qb->createNamedParameter($share->getPermissions()));
+
+ // Set who created this share
+ $qb->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()->getUID()));
+
+ // Set who is the owner of this file/folder (and this the owner of the share)
+ $qb->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()->getUID()));
+
+ // Set the file target
+ $qb->setValue('file_target', $qb->createNamedParameter($share->getTarget()));
+
+ // Set the time this share was created
+ $qb->setValue('stime', $qb->createNamedParameter(time()));
+
+ // insert the data and fetch the id of the share
+ $this->dbConn->beginTransaction();
+ $qb->execute();
+ $id = $this->dbConn->lastInsertId('*PREFIX*share');
+ $this->dbConn->commit();
+
+ // Now fetch the inserted share and create a complete share object
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('*PREFIX*share')
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
+
+ $cursor = $qb->execute();
+ $data = $cursor->fetch();
+ $cursor->closeCursor();
+
+ if ($data === false) {
+ throw new ShareNotFound();
+ }
+
+ $share = $this->createShare($data);
+ return $share;
}
/**
@@ -170,11 +249,29 @@ class DefaultShareProvider implements IShareProvider {
/**
* Get shares for a given path
*
- * @param \OCP\IUser $user
* @param \OCP\Files\Node $path
* @return IShare[]
*/
- public function getSharesByPath(IUser $user, Node $path) {
+ public function getSharesByPath(Node $path) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $cursor = $qb->select('*')
+ ->from('share')
+ ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
+ ->andWhere(
+ $qb->expr()->orX(
+ $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
+ $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))
+ )
+ )->execute();
+
+ $shares = [];
+ while($data = $cursor->fetch()) {
+ $shares[] = $this->createShare($data);
+ }
+ $cursor->closeCursor();
+
+ return $shares;
}
/**
@@ -223,16 +320,21 @@ class DefaultShareProvider implements IShareProvider {
$share->setSharedWith($data['share_with']);
}
- $share->setSharedBy($this->userManager->get($data['uid_owner']));
-
- // TODO: getById can return an array. How to handle this properly??
- $folder = $this->rootFolder->getUserFolder($share->getSharedBy()->getUID());
- $path = $folder->getById((int)$data['file_source'])[0];
+ if ($data['uid_initiator'] === null) {
+ //OLD SHARE
+ $share->setSharedBy($this->userManager->get($data['uid_owner']));
+ $folder = $this->rootFolder->getUserFolder($share->getSharedBy()->getUID());
+ $path = $folder->getById((int)$data['file_source'])[0];
- $owner = $path->getOwner();
- $share->setShareOwner($owner);
+ $owner = $path->getOwner();
+ $share->setShareOwner($owner);
+ } else {
+ //New share!
+ $share->setSharedBy($this->userManager->get($data['uid_initiator']));
+ $share->setShareOwner($this->userManager->get($data['uid_owner']));
+ }
- $path = $this->rootFolder->getUserFolder($owner->getUID())->getById((int)$data['file_source'])[0];
+ $path = $this->rootFolder->getUserFolder($share->getShareOwner()->getUID())->getById((int)$data['file_source'])[0];
$share->setPath($path);
if ($data['expiration'] !== null) {
diff --git a/lib/private/share20/ishare.php b/lib/private/share20/ishare.php
index 2e54da7a029..a149c578fb2 100644
--- a/lib/private/share20/ishare.php
+++ b/lib/private/share20/ishare.php
@@ -101,7 +101,7 @@ interface IShare {
* @param \DateTime $expireDate
* @return Share The modified object
*/
- public function setExpirationDate(\DateTime $expireDate);
+ public function setExpirationDate($expireDate);
/**
* Get the share expiration date
@@ -111,6 +111,14 @@ interface IShare {
public function getExpirationDate();
/**
+ * Set the sharer of the path
+ *
+ * @param IUser|string $sharedBy
+ * @return Share The modified object
+ */
+ public function setSharedBy($sharedBy);
+
+ /**
* Get share sharer
*
* @return IUser|string
@@ -118,6 +126,15 @@ interface IShare {
public function getSharedBy();
/**
+ * Set the original share owner (who owns the path)
+ *
+ * @param IUser|string
+ *
+ * @return Share The modified object
+ */
+ public function setShareOwner($shareOwner);
+
+ /**
* Get the original share owner (who owns the path)
*
* @return IUser|string
@@ -141,6 +158,14 @@ interface IShare {
public function getPassword();
/**
+ * Set the token
+ *
+ * @param string $token
+ * @return Share The modified object
+ */
+ public function setToken($token);
+
+ /**
* Get the token
*
* @return string
@@ -155,6 +180,14 @@ interface IShare {
public function getParent();
/**
+ * Set the target of this share
+ *
+ * @param string $target
+ * @return Share The modified object
+ */
+ public function setTarget($target);
+
+ /**
* Get the target of this share
*
* @return string
diff --git a/lib/private/share20/ishareprovider.php b/lib/private/share20/ishareprovider.php
index 56a550acf71..97a2b728d5f 100644
--- a/lib/private/share20/ishareprovider.php
+++ b/lib/private/share20/ishareprovider.php
@@ -81,11 +81,10 @@ interface IShareProvider {
/**
* Get shares for a given path
*
- * @param \OCP\IUser $user
* @param \OCP\Files\Node $path
* @return IShare[]
*/
- public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path);
+ public function getSharesByPath(\OCP\Files\Node $path);
/**
* Get shared with the given user
diff --git a/lib/private/share20/manager.php b/lib/private/share20/manager.php
index 882b281c490..8d753061c0c 100644
--- a/lib/private/share20/manager.php
+++ b/lib/private/share20/manager.php
@@ -21,53 +21,458 @@
namespace OC\Share20;
-use OCP\IAppConfig;
+use OCP\IConfig;
+use OCP\IL10N;
use OCP\ILogger;
+use OCP\Security\ISecureRandom;
+use OCP\Security\IHasher;
+use OCP\Files\Mount\IMountManager;
+use OCP\IGroupManager;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\IUser;
use OC\Share20\Exception\ShareNotFound;
+use OC\HintException;
/**
* This class is the communication hub for all sharing related operations.
*/
class Manager {
- /**
- * @var IShareProvider[]
- */
+ /** @var IShareProvider[] */
private $defaultProvider;
/** @var ILogger */
private $logger;
- /** @var IAppConfig */
- private $appConfig;
+ /** @var IConfig */
+ private $config;
+
+ /** @var ISecureRandom */
+ private $secureRandom;
+
+ /** @var IHasher */
+ private $hasher;
+
+ /** @var IMountManager */
+ private $mountManager;
+
+ /** @var IGroupManager */
+ private $groupManager;
+
+ /** @var IL10N */
+ private $l;
/**
* Manager constructor.
*
* @param ILogger $logger
- * @param IAppConfig $appConfig
+ * @param IConfig $config
* @param IShareProvider $defaultProvider
+ * @param ISecureRandom $secureRandom
+ * @param IHasher $hasher
+ * @param IMountManager $mountManager
+ * @param IGroupManager $groupManager
+ * @param IL10N $l
*/
public function __construct(
ILogger $logger,
- IAppConfig $appConfig,
- IShareProvider $defaultProvider
+ IConfig $config,
+ IShareProvider $defaultProvider,
+ ISecureRandom $secureRandom,
+ IHasher $hasher,
+ IMountManager $mountManager,
+ IGroupManager $groupManager,
+ IL10N $l
) {
$this->logger = $logger;
- $this->appConfig = $appConfig;
+ $this->config = $config;
+ $this->secureRandom = $secureRandom;
+ $this->hasher = $hasher;
+ $this->mountManager = $mountManager;
+ $this->groupManager = $groupManager;
+ $this->l = $l;
// TEMP SOLUTION JUST TO GET STARTED
$this->defaultProvider = $defaultProvider;
}
/**
+ * Verify if a password meets all requirements
+ *
+ * @param string $password
+ * @throws \Exception
+ */
+ protected function verifyPassword($password) {
+ if ($password === null) {
+ // No password is set, check if this is allowed.
+ if ($this->shareApiLinkEnforcePassword()) {
+ throw new \InvalidArgumentException('Passwords are enforced for link shares');
+ }
+
+ return;
+ }
+
+ // Let others verify the password
+ $accepted = true;
+ $message = '';
+ \OCP\Util::emitHook('\OC\Share', 'verifyPassword', [
+ 'password' => $password,
+ 'accepted' => &$accepted,
+ 'message' => &$message
+ ]);
+
+ if (!$accepted) {
+ throw new \Exception($message);
+ }
+ }
+
+ /**
+ * Check for generic requirements before creating a share
+ *
+ * @param IShare $share
+ * @throws \Exception
+ */
+ protected function generalCreateChecks(IShare $share) {
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ // We expect a valid user as sharedWith for user shares
+ if (!($share->getSharedWith() instanceof \OCP\IUser)) {
+ throw new \InvalidArgumentException('SharedWith should be an IUser');
+ }
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ // We expect a valid group as sharedWith for group shares
+ if (!($share->getSharedWith() instanceof \OCP\IGroup)) {
+ throw new \InvalidArgumentException('SharedWith should be an IGroup');
+ }
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ if ($share->getSharedWith() !== null) {
+ throw new \InvalidArgumentException('SharedWith should be empty');
+ }
+ } else {
+ // We can't handle other types yet
+ throw new \InvalidArgumentException('unkown share type');
+ }
+
+ // Verify the initiator of the share is et
+ if ($share->getSharedBy() === null) {
+ throw new \InvalidArgumentException('SharedBy should be set');
+ }
+
+ // Cannot share with yourself
+ if ($share->getSharedWith() === $share->getSharedBy()) {
+ throw new \InvalidArgumentException('Can\'t share with yourself');
+ }
+
+ // The path should be set
+ if ($share->getPath() === null) {
+ throw new \InvalidArgumentException('Path should be set');
+ }
+ // And it should be a file or a folder
+ if (!($share->getPath() instanceof \OCP\Files\File) &&
+ !($share->getPath() instanceof \OCP\Files\Folder)) {
+ throw new \InvalidArgumentException('Path should be either a file or a folder');
+ }
+
+ // Check if we actually have share permissions
+ if (!$share->getPath()->isShareable()) {
+ $message_t = $this->l->t('You are not allowed to share %s', [$share->getPath()->getPath()]);
+ throw new HintException($message_t, $message_t, 404);
+ }
+
+ // Permissions should be set
+ if ($share->getPermissions() === null) {
+ throw new \InvalidArgumentException('A share requires permissions');
+ }
+
+ // Check that we do not share with more permissions than we have
+ if ($share->getPermissions() & ~$share->getPath()->getPermissions()) {
+ $message_t = $this->l->t('Cannot increase permissions of %s', [$share->getPath()->getPath()]);
+ throw new HintException($message_t, $message_t, 404);
+ }
+
+ // Check that read permissions are always set
+ if (($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
+ throw new \InvalidArgumentException('Shares need at least read permissions');
+ }
+ }
+
+ /**
+ * Validate if the expiration date fits the system settings
+ *
+ * @param \DateTime $expireDate The current expiration date (can be null)
+ * @return \DateTime|null The expiration date or null if $expireDate was null and it is not required
+ * @throws \OC\HintException
+ */
+ protected function validateExpiredate($expireDate) {
+
+ if ($expireDate !== null) {
+ //Make sure the expiration date is a date
+ $expireDate->setTime(0, 0, 0);
+
+ $date = new \DateTime();
+ $date->setTime(0, 0, 0);
+ if ($date >= $expireDate) {
+ $message = $this->l->t('Expiration date is in the past');
+ throw new \OC\HintException($message, $message, 404);
+ }
+ }
+
+ // If we enforce the expiration date check that is does not exceed
+ if ($this->shareApiLinkDefaultExpireDateEnforced()) {
+ if ($expireDate === null) {
+ throw new \InvalidArgumentException('Expiration date is enforced');
+ }
+
+ $date = new \DateTime();
+ $date->setTime(0, 0, 0);
+ $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
+ if ($date < $expireDate) {
+ $message = $this->l->t('Cannot set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
+ throw new \OC\HintException($message, $message, 404);
+ }
+
+ return $expireDate;
+ }
+
+ // If expiredate is empty set a default one if there is a default
+ if ($expireDate === null && $this->shareApiLinkDefaultExpireDate()) {
+ $date = new \DateTime();
+ $date->setTime(0,0,0);
+ $date->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
+ return $date;
+ }
+
+ return $expireDate;
+ }
+
+
+ /**
+ * Check for pre share requirements for use shares
+ *
+ * @param IShare $share
+ * @throws \Exception
+ */
+ protected function userCreateChecks(IShare $share) {
+ // Check if we can share with group members only
+ if ($this->shareWithGroupMembersOnly()) {
+ // Verify we can share with this user
+ $groups = array_intersect(
+ $this->groupManager->getUserGroupIds($share->getSharedBy()),
+ $this->groupManager->getUserGroupIds($share->getSharedWith())
+ );
+ if (empty($groups)) {
+ throw new \Exception('Only sharing with group members is allowed');
+ }
+ }
+
+ /*
+ * TODO: Could be costly, fix
+ *
+ * Also this is not what we want in the future.. then we want to squash identical shares.
+ */
+ $existingShares = $this->defaultProvider->getSharesByPath($share->getPath());
+ foreach($existingShares as $existingShare) {
+ // Identical share already existst
+ if ($existingShare->getSharedWith() === $share->getSharedWith()) {
+ throw new \Exception('Path already shared with this user');
+ }
+
+ // The share is already shared with this user via a group share
+ if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP &&
+ $existingShare->getSharedWith()->inGroup($share->getSharedWith()) &&
+ $existingShare->getShareOwner() !== $share->getShareOwner()) {
+ throw new \Exception('Path already shared with this user');
+ }
+ }
+ }
+
+ /**
+ * Check for pre share requirements for group shares
+ *
+ * @param IShare $share
+ * @throws \Exception
+ */
+ protected function groupCreateChecks(IShare $share) {
+ // Verify if the user can share with this group
+ if ($this->shareWithGroupMembersOnly()) {
+ if (!$share->getSharedWith()->inGroup($share->getSharedBy())) {
+ throw new \Exception('Only sharing within your own groups is allowed');
+ }
+ }
+
+ /*
+ * TODO: Could be costly, fix
+ *
+ * Also this is not what we want in the future.. then we want to squash identical shares.
+ */
+ $existingShares = $this->defaultProvider->getSharesByPath($share->getPath());
+ foreach($existingShares as $existingShare) {
+ if ($existingShare->getSharedWith() === $share->getSharedWith()) {
+ throw new \Exception('Path already shared with this group');
+ }
+ }
+ }
+
+ /**
+ * Check for pre share requirements for link shares
+ *
+ * @param IShare $share
+ * @throws \Exception
+ */
+ protected function linkCreateChecks(IShare $share) {
+ // Are link shares allowed?
+ if (!$this->shareApiAllowLinks()) {
+ throw new \Exception('Link sharing not allowed');
+ }
+
+ // Link shares by definition can't have share permissions
+ if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
+ throw new \InvalidArgumentException('Link shares can\'t have reshare permissions');
+ }
+
+ // We don't allow deletion on link shares
+ if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
+ throw new \InvalidArgumentException('Link shares can\'t have delete permissions');
+ }
+
+ // Check if public upload is allowed
+ if (!$this->shareApiLinkAllowPublicUpload() &&
+ ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE))) {
+ throw new \InvalidArgumentException('Public upload not allowed');
+ }
+ }
+
+ /**
+ * @param File|Folder $path
+ */
+ protected function pathCreateChecks($path) {
+ // Make sure that we do not share a path that contains a shared mountpoint
+ if ($path instanceof \OCP\Files\Folder) {
+ $mounts = $this->mountManager->findIn($path->getPath());
+ foreach($mounts as $mount) {
+ if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
+ throw new \InvalidArgumentException('Path contains files shared with you');
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if the user that is sharing can actually share
+ *
+ * @param IShare $share
+ * @return bool
+ */
+ protected function canShare(IShare $share) {
+ if (!$this->shareApiEnabled()) {
+ return false;
+ }
+
+ if ($this->isSharingDisabledForUser($share->getSharedBy())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Share a path
*
- * @param Share $share
+ * @param IShare $share
* @return Share The share object
+ * @throws \Exception
+ *
+ * TODO: handle link share permissions or check them
*/
- public function createShare(Share $share) {
+ public function createShare(IShare $share) {
+ if (!$this->canShare($share)) {
+ throw new \Exception('The Share API is disabled');
+ }
+
+ $this->generalCreateChecks($share);
+
+ //Verify share type
+ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+ $this->userCreateChecks($share);
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+ $this->groupCreateChecks($share);
+ } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
+ $this->linkCreateChecks($share);
+
+ /*
+ * For now ignore a set token.
+ */
+ $share->setToken(
+ $this->secureRandom->generate(
+ \OC\Share\Constants::TOKEN_LENGTH,
+ \OCP\Security\ISecureRandom::CHAR_LOWER.
+ \OCP\Security\ISecureRandom::CHAR_UPPER.
+ \OCP\Security\ISecureRandom::CHAR_DIGITS
+ )
+ );
+
+ //Verify the expiration date
+ $share->setExpirationDate($this->validateExpiredate($share->getExpirationDate()));
+
+ //Verify the password
+ $this->verifyPassword($share->getPassword());
+
+ // If a password is set. Hash it!
+ if ($share->getPassword() !== null) {
+ $share->setPassword($this->hasher->hash($share->getPassword()));
+ }
+ }
+
+ // Verify if there are any issues with the path
+ $this->pathCreateChecks($share->getPath());
+
+ // On creation of a share the owner is always the owner of the path
+ $share->setShareOwner($share->getPath()->getOwner());
+
+ // Generate the target
+ $target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getPath()->getName();
+ $target = \OC\Files\Filesystem::normalizePath($target);
+ $share->setTarget($target);
+
+ // Pre share hook
+ $run = true;
+ $error = '';
+ $preHookData = [
+ 'itemType' => $share->getPath() instanceof \OCP\Files\File ? 'file' : 'folder',
+ 'itemSource' => $share->getPath()->getId(),
+ 'shareType' => $share->getShareType(),
+ 'uidOwner' => $share->getSharedBy()->getUID(),
+ 'permissions' => $share->getPermissions(),
+ 'fileSource' => $share->getPath()->getId(),
+ 'expiration' => $share->getExpirationDate(),
+ 'token' => $share->getToken(),
+ 'run' => &$run,
+ 'error' => &$error
+ ];
+ \OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData);
+
+ if ($run === false) {
+ throw new \Exception($error);
+ }
+
+ $share = $this->defaultProvider->create($share);
+
+ // Post share hook
+ $postHookData = [
+ 'itemType' => $share->getPath() instanceof \OCP\Files\File ? 'file' : 'folder',
+ 'itemSource' => $share->getPath()->getId(),
+ 'shareType' => $share->getShareType(),
+ 'uidOwner' => $share->getSharedBy()->getUID(),
+ 'permissions' => $share->getPermissions(),
+ 'fileSource' => $share->getPath()->getId(),
+ 'expiration' => $share->getExpirationDate(),
+ 'token' => $share->getToken(),
+ 'id' => $share->getId(),
+ ];
+ \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
+
+ return $share;
}
/**
@@ -251,4 +656,115 @@ class Manager {
*/
public function getAccessList(\OCP\Files\Node $path) {
}
+
+ /**
+ * Create a new share
+ * @return IShare;
+ */
+ public function newShare() {
+ return new \OC\Share20\Share();
+ }
+
+ /**
+ * Is the share API enabled
+ *
+ * @return bool
+ */
+ public function shareApiEnabled() {
+ return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
+ }
+
+ /**
+ * Is public link sharing enabled
+ *
+ * @return bool
+ */
+ public function shareApiAllowLinks() {
+ return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
+ }
+
+ /**
+ * Is password on public link requires
+ *
+ * @return bool
+ */
+ public function shareApiLinkEnforcePassword() {
+ return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
+ }
+
+ /**
+ * Is default expire date enabled
+ *
+ * @return bool
+ */
+ public function shareApiLinkDefaultExpireDate() {
+ return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
+ }
+
+ /**
+ * Is default expire date enforced
+ *`
+ * @return bool
+ */
+ public function shareApiLinkDefaultExpireDateEnforced() {
+ return $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
+ }
+
+ /**
+ * Number of default expire days
+ *shareApiLinkAllowPublicUpload
+ * @return int
+ */
+ public function shareApiLinkDefaultExpireDays() {
+ return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
+ }
+
+ /**
+ * Allow public upload on link shares
+ *
+ * @return bool
+ */
+ public function shareApiLinkAllowPublicUpload() {
+ return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
+ }
+
+ /**
+ * check if user can only share with group members
+ * @return bool
+ */
+ public function shareWithGroupMembersOnly() {
+ return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
+ }
+
+
+ /**
+ * Copied from \OC_Util::isSharingDisabledForUser
+ *
+ * TODO: Deprecate fuction from OC_Util
+ *
+ * @param IUser $user
+ * @return bool
+ */
+ public function isSharingDisabledForUser($user) {
+ if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
+ $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
+ $excludedGroups = json_decode($groupsList);
+ if (is_null($excludedGroups)) {
+ $excludedGroups = explode(',', $groupsList);
+ $newValue = json_encode($excludedGroups);
+ $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
+ }
+ $usersGroups = $this->groupManager->getUserGroupIds($user);
+ if (!empty($usersGroups)) {
+ $remainingGroups = array_diff($usersGroups, $excludedGroups);
+ // if the user is only in groups which are disabled for sharing then
+ // sharing is also disabled for the user
+ if (empty($remainingGroups)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
}
diff --git a/lib/private/share20/share.php b/lib/private/share20/share.php
index b7ce38ac61d..4827000eefa 100644
--- a/lib/private/share20/share.php
+++ b/lib/private/share20/share.php
@@ -163,7 +163,7 @@ class Share implements IShare {
* @param \DateTime $expireDate
* @return Share The modified object
*/
- public function setExpirationDate(\DateTime $expireDate) {
+ public function setExpirationDate($expireDate) {
//TODO checks
$this->expireDate = $expireDate;
diff --git a/lib/private/systemconfig.php b/lib/private/systemconfig.php
index 94b815aebd7..fb8c18123d7 100644
--- a/lib/private/systemconfig.php
+++ b/lib/private/systemconfig.php
@@ -44,12 +44,19 @@ class SystemConfig {
'objectstore' => ['arguments' => ['password' => true]],
];
+ /** @var Config */
+ private $config;
+
+ public function __construct(Config $config) {
+ $this->config = $config;
+ }
+
/**
* Lists all available config keys
* @return array an array of key names
*/
public function getKeys() {
- return \OC_Config::getKeys();
+ return $this->config->getKeys();
}
/**
@@ -59,7 +66,7 @@ class SystemConfig {
* @param mixed $value the value that should be stored
*/
public function setValue($key, $value) {
- \OC_Config::setValue($key, $value);
+ $this->config->setValue($key, $value);
}
/**
@@ -69,7 +76,7 @@ class SystemConfig {
* If value is null, the config key will be deleted
*/
public function setValues(array $configs) {
- \OC_Config::setValues($configs);
+ $this->config->setValues($configs);
}
/**
@@ -80,7 +87,7 @@ class SystemConfig {
* @return mixed the value or $default
*/
public function getValue($key, $default = '') {
- return \OC_Config::getValue($key, $default);
+ return $this->config->getValue($key, $default);
}
/**
@@ -106,7 +113,7 @@ class SystemConfig {
* @param string $key the key of the value, under which it was saved
*/
public function deleteValue($key) {
- \OC_Config::deleteKey($key);
+ $this->config->deleteKey($key);
}
/**
diff --git a/lib/private/tags.php b/lib/private/tags.php
index 09cb7618c02..c621aa3cf8f 100644
--- a/lib/private/tags.php
+++ b/lib/private/tags.php
@@ -215,7 +215,7 @@ class Tags implements \OCP\ITags {
$entries = array();
try {
- $conn = \OC_DB::getConnection();
+ $conn = \OC::$server->getDatabaseConnection();
$chunks = array_chunk($objIds, 900, false);
foreach ($chunks as $chunk) {
$result = $conn->executeQuery(
diff --git a/lib/private/template.php b/lib/private/template.php
index d794dacac23..c2528c26851 100644
--- a/lib/private/template.php
+++ b/lib/private/template.php
@@ -119,7 +119,6 @@ class OC_Template extends \OC\Template\Base {
// avatars
if (\OC::$server->getSystemConfig()->getValue('enable_avatars', true) === true) {
- \OC_Util::addScript('avatar', null, true);
\OC_Util::addScript('jquery.avatar', null, true);
\OC_Util::addScript('placeholder', null, true);
}
@@ -162,6 +161,8 @@ class OC_Template extends \OC\Template\Base {
}
if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE])) {
+ // polyfill for btoa/atob for IE friends
+ OC_Util::addVendorScript('base64/base64');
// shim for the davclient.js library
\OCP\Util::addScript('files/iedavclient');
}
diff --git a/lib/private/template/functions.php b/lib/private/template/functions.php
index d156d26f9ce..982ecde5850 100644
--- a/lib/private/template/functions.php
+++ b/lib/private/template/functions.php
@@ -146,7 +146,7 @@ function component($app, $file) {
* For further information have a look at OC_Helper::linkTo
*/
function link_to( $app, $file, $args = array() ) {
- return OC_Helper::linkTo( $app, $file, $args );
+ return \OC::$server->getURLGenerator()->linkTo($app, $file, $args);
}
/**
@@ -173,11 +173,9 @@ function image_path( $app, $image ) {
* make OC_Helper::mimetypeIcon available as a simple function
* @param string $mimetype mimetype
* @return string link to the image
- *
- * For further information have a look at OC_Helper::mimetypeIcon
*/
function mimetype_icon( $mimetype ) {
- return OC_Helper::mimetypeIcon( $mimetype );
+ return \OC::$server->getMimeTypeDetector()->mimeTypeIcon( $mimetype );
}
/**
diff --git a/lib/private/templatelayout.php b/lib/private/templatelayout.php
index 1a6a07ddc9f..bf25b2d31a9 100644
--- a/lib/private/templatelayout.php
+++ b/lib/private/templatelayout.php
@@ -136,7 +136,13 @@ class OC_TemplateLayout extends OC_Template {
$this->assign('user_uid', OC_User::getUser());
$this->assign('appsmanagement_active', $appsMgmtActive);
$this->assign('enableAvatars', $this->config->getSystemValue('enable_avatars', true));
- $this->assign('userAvatarSet', \OC_Helper::userAvatarSet(OC_User::getUser()));
+
+ if (OC_User::getUser() === false) {
+ $this->assign('userAvatarSet', false);
+ } else {
+ $this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(OC_User::getUser())->exists());
+ }
+
} else if ($renderAs == 'error') {
parent::__construct('core', 'layout.guest', '', false);
$this->assign('bodyid', 'body-login');
@@ -153,20 +159,20 @@ class OC_TemplateLayout extends OC_Template {
if(empty(self::$versionHash)) {
$v = OC_App::getAppVersions();
- $v['core'] = implode('.', \OC_Util::getVersion());
+ $v['core'] = implode('.', \OCP\Util::getVersion());
self::$versionHash = md5(implode(',', $v));
}
$useAssetPipeline = self::isAssetPipelineEnabled();
if ($useAssetPipeline) {
- $this->append( 'jsfiles', OC_Helper::linkToRoute('js_config', array('v' => self::$versionHash)));
+ $this->append( 'jsfiles', \OC::$server->getURLGenerator()->linkToRoute('js_config', ['v' => self::$versionHash]));
$this->generateAssets();
} else {
// Add the js files
$jsFiles = self::findJavascriptFiles(OC_Util::$scripts);
$this->assign('jsfiles', array());
if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
- $this->append( 'jsfiles', OC_Helper::linkToRoute('js_config', array('v' => self::$versionHash)));
+ $this->append( 'jsfiles', \OC::$server->getURLGenerator()->linkToRoute('js_config', ['v' => self::$versionHash]));
}
foreach($jsFiles as $info) {
$web = $info[1];
@@ -275,8 +281,8 @@ class OC_TemplateLayout extends OC_Template {
$writer->writeAsset($cssCollection);
}
- $this->append('jsfiles', OC_Helper::linkTo('assets', "$jsHash.js"));
- $this->append('cssfiles', OC_Helper::linkTo('assets', "$cssHash.css"));
+ $this->append('jsfiles', \OC::$server->getURLGenerator()->linkTo('assets', "$jsHash.js"));
+ $this->append('cssfiles', \OC::$server->getURLGenerator()->linkTo('assets', "$cssHash.css"));
}
/**
diff --git a/lib/private/updater.php b/lib/private/updater.php
index 366ad2555a8..9ec72bab2f9 100644
--- a/lib/private/updater.php
+++ b/lib/private/updater.php
@@ -155,7 +155,7 @@ class Updater extends BasicEmitter {
$this->config->setAppValue('core', 'installedat', microtime(true));
}
- $version = \OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
$version['installed'] = $this->config->getAppValue('core', 'installedat');
$version['updated'] = $this->config->getAppValue('core', 'lastupdatedat');
$version['updatechannel'] = \OC_Util::getChannel();
@@ -177,6 +177,8 @@ class Updater extends BasicEmitter {
$tmp['versionstring'] = (string)$data->versionstring;
$tmp['url'] = (string)$data->url;
$tmp['web'] = (string)$data->web;
+ } else {
+ libxml_clear_errors();
}
} else {
$data = [];
@@ -206,7 +208,7 @@ class Updater extends BasicEmitter {
}
$installedVersion = $this->config->getSystemValue('version', '0.0.0');
- $currentVersion = implode('.', \OC_Util::getVersion());
+ $currentVersion = implode('.', \OCP\Util::getVersion());
$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
$success = true;
@@ -254,7 +256,7 @@ class Updater extends BasicEmitter {
*/
public function isUpgradePossible($oldVersion, $newVersion, $allowedPreviousVersion) {
return (version_compare($allowedPreviousVersion, $oldVersion, '<=')
- && version_compare($oldVersion, $newVersion, '<='));
+ && (version_compare($oldVersion, $newVersion, '<=') || $this->config->getSystemValue('debug', false)));
}
/**
@@ -351,7 +353,7 @@ class Updater extends BasicEmitter {
}
// only set the final version if everything went well
- $this->config->setSystemValue('version', implode('.', \OC_Util::getVersion()));
+ $this->config->setSystemValue('version', implode('.', \OCP\Util::getVersion()));
}
}
@@ -470,7 +472,7 @@ class Updater extends BasicEmitter {
private function checkAppsRequirements() {
$isCoreUpgrade = $this->isCodeUpgrade();
$apps = OC_App::getEnabledApps();
- $version = OC_Util::getVersion();
+ $version = \OCP\Util::getVersion();
$disabledApps = [];
foreach ($apps as $app) {
// check if the app is compatible with this version of ownCloud
@@ -507,7 +509,7 @@ class Updater extends BasicEmitter {
*/
private function isCodeUpgrade() {
$installedVersion = $this->config->getSystemValue('version', '0.0.0');
- $currentVersion = implode('.', OC_Util::getVersion());
+ $currentVersion = implode('.', \OCP\Util::getVersion());
if (version_compare($currentVersion, $installedVersion, '>')) {
return true;
}
diff --git a/lib/private/user.php b/lib/private/user.php
index 74441d9175a..fa1cea9072f 100644
--- a/lib/private/user.php
+++ b/lib/private/user.php
@@ -66,14 +66,6 @@ class OC_User {
return OC::$server->getUserSession();
}
- /**
- * @return \OC\User\Manager
- * @deprecated Use \OC::$server->getUserManager()
- */
- public static function getManager() {
- return OC::$server->getUserManager();
- }
-
private static $_backends = array();
private static $_usedBackends = array();
@@ -84,44 +76,6 @@ class OC_User {
private static $incognitoMode = false;
/**
- * registers backend
- *
- * @param string $backend name of the backend
- * @deprecated Add classes by calling OC_User::useBackend() with a class instance instead
- * @return bool
- *
- * Makes a list of backends that can be used by other modules
- */
- public static function registerBackend($backend) {
- self::$_backends[] = $backend;
- return true;
- }
-
- /**
- * gets available backends
- *
- * @deprecated
- * @return array an array of backends
- *
- * Returns the names of all backends.
- */
- public static function getBackends() {
- return self::$_backends;
- }
-
- /**
- * gets used backends
- *
- * @deprecated
- * @return array an array of backends
- *
- * Returns the names of all used backends.
- */
- public static function getUsedBackends() {
- return array_keys(self::$_usedBackends);
- }
-
- /**
* Adds the backend to the list of used backends
*
* @param string|OC_User_Interface $backend default: database The backend to use for user management
@@ -132,7 +86,7 @@ class OC_User {
public static function useBackend($backend = 'database') {
if ($backend instanceof OC_User_Interface) {
self::$_usedBackends[get_class($backend)] = $backend;
- self::getManager()->registerBackend($backend);
+ \OC::$server->getUserManager()->registerBackend($backend);
} else {
// You'll never know what happens
if (null === $backend OR !is_string($backend)) {
@@ -146,17 +100,17 @@ class OC_User {
case 'sqlite':
\OCP\Util::writeLog('core', 'Adding user backend ' . $backend . '.', \OCP\Util::DEBUG);
self::$_usedBackends[$backend] = new OC_User_Database();
- self::getManager()->registerBackend(self::$_usedBackends[$backend]);
+ \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
break;
case 'dummy':
self::$_usedBackends[$backend] = new \Test\Util\User\Dummy();
- self::getManager()->registerBackend(self::$_usedBackends[$backend]);
+ \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
break;
default:
\OCP\Util::writeLog('core', 'Adding default user backend ' . $backend . '.', \OCP\Util::DEBUG);
$className = 'OC_USER_' . strToUpper($backend);
self::$_usedBackends[$backend] = new $className();
- self::getManager()->registerBackend(self::$_usedBackends[$backend]);
+ \OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
break;
}
}
@@ -168,7 +122,7 @@ class OC_User {
*/
public static function clearBackends() {
self::$_usedBackends = array();
- self::getManager()->clearBackends();
+ \OC::$server->getUserManager()->clearBackends();
}
/**
@@ -176,7 +130,7 @@ class OC_User {
*/
public static function setupBackends() {
OC_App::loadApps(array('prelogin'));
- $backends = OC_Config::getValue('user_backends', array());
+ $backends = \OC::$server->getSystemConfig()->getValue('user_backends', array());
foreach ($backends as $i => $config) {
$class = $config['class'];
$arguments = $config['arguments'];
@@ -199,42 +153,6 @@ class OC_User {
}
/**
- * Create a new user
- *
- * @param string $uid The username of the user to create
- * @param string $password The password of the new user
- * @throws Exception
- * @return bool true/false
- *
- * Creates a new user. Basic checking of username is done in OC_User
- * itself, not in its subclasses.
- *
- * Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-"
- * @deprecated Use \OC::$server->getUserManager()->createUser($uid, $password)
- */
- public static function createUser($uid, $password) {
- return self::getManager()->createUser($uid, $password);
- }
-
- /**
- * delete a user
- *
- * @param string $uid The username of the user to delete
- * @return bool
- *
- * Deletes a user
- * @deprecated Use \OC::$server->getUserManager()->get() and then run delete() on the return
- */
- public static function deleteUser($uid) {
- $user = self::getManager()->get($uid);
- if ($user) {
- return $user->delete();
- } else {
- return false;
- }
- }
-
- /**
* Try to login a user
*
* @param string $loginname The login name of the user to log in
@@ -244,7 +162,6 @@ class OC_User {
* Log in a user and regenerate a new session - if the password is ok
*/
public static function login($loginname, $password) {
- session_regenerate_id(true);
$result = self::getUserSession()->login($loginname, $password);
if ($result) {
//we need to pass the user name, which may differ from login name
@@ -343,7 +260,7 @@ class OC_User {
if (is_null($displayName)) {
$displayName = $uid;
}
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->setDisplayName($displayName);
} else {
@@ -452,7 +369,7 @@ class OC_User {
*/
public static function getDisplayName($uid = null) {
if ($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->getDisplayName();
} else {
@@ -490,7 +407,7 @@ class OC_User {
* Change the password of a user
*/
public static function setPassword($uid, $password, $recoveryPassword = null) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->setPassword($password, $recoveryPassword);
} else {
@@ -507,7 +424,7 @@ class OC_User {
* Check whether a specified user can change his avatar
*/
public static function canUserChangeAvatar($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->canChangeAvatar();
} else {
@@ -524,7 +441,7 @@ class OC_User {
* Check whether a specified user can change his password
*/
public static function canUserChangePassword($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->canChangePassword();
} else {
@@ -541,7 +458,7 @@ class OC_User {
* Check whether a specified user can change his display name
*/
public static function canUserChangeDisplayName($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->canChangeDisplayName();
} else {
@@ -560,7 +477,7 @@ class OC_User {
* returns the user id or false
*/
public static function checkPassword($uid, $password) {
- $manager = self::getManager();
+ $manager = \OC::$server->getUserManager();
$username = $manager->checkPassword($uid, $password);
if ($username !== false) {
return $username->getUID();
@@ -576,11 +493,11 @@ class OC_User {
* @deprecated Use \OC::$server->getUserManager->getHome()
*/
public static function getHome($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->getHome();
} else {
- return OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
+ return \OC::$server->getSystemConfig()->getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
}
}
@@ -595,7 +512,7 @@ class OC_User {
* @param integer $offset
*/
public static function getUsers($search = '', $limit = null, $offset = null) {
- $users = self::getManager()->search($search, $limit, $offset);
+ $users = \OC::$server->getUserManager()->search($search, $limit, $offset);
$uids = array();
foreach ($users as $user) {
$uids[] = $user->getUID();
@@ -616,7 +533,7 @@ class OC_User {
*/
public static function getDisplayNames($search = '', $limit = null, $offset = null) {
$displayNames = array();
- $users = self::getManager()->searchDisplayName($search, $limit, $offset);
+ $users = \OC::$server->getUserManager()->searchDisplayName($search, $limit, $offset);
foreach ($users as $user) {
$displayNames[$user->getUID()] = $user->getDisplayName();
}
@@ -630,7 +547,7 @@ class OC_User {
* @return boolean
*/
public static function userExists($uid) {
- return self::getManager()->userExists($uid);
+ return \OC::$server->getUserManager()->userExists($uid);
}
/**
@@ -639,7 +556,7 @@ class OC_User {
* @param string $uid the user to disable
*/
public static function disableUser($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
$user->setEnabled(false);
}
@@ -651,7 +568,7 @@ class OC_User {
* @param string $uid
*/
public static function enableUser($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
$user->setEnabled(true);
}
@@ -664,7 +581,7 @@ class OC_User {
* @return bool
*/
public static function isEnabled($uid) {
- $user = self::getManager()->get($uid);
+ $user = \OC::$server->getUserManager()->get($uid);
if ($user) {
return $user->isEnabled();
} else {
diff --git a/lib/private/user/database.php b/lib/private/user/database.php
index 98850771212..5bee509e8bd 100644
--- a/lib/private/user/database.php
+++ b/lib/private/user/database.php
@@ -210,7 +210,7 @@ class OC_User_Database extends OC_User_Backend implements \OCP\IUserBackend {
$query = OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)');
$result = $query->execute(array($uid));
- if (OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('core', OC_DB::getErrorMessage(), \OCP\Util::ERROR);
return false;
}
@@ -287,7 +287,7 @@ class OC_User_Database extends OC_User_Backend implements \OCP\IUserBackend {
public function countUsers() {
$query = OC_DB::prepare('SELECT COUNT(*) FROM `*PREFIX*users`');
$result = $query->execute();
- if (OC_DB::isError($result)) {
+ if ($result === false) {
\OCP\Util::writeLog('core', OC_DB::getErrorMessage(), \OCP\Util::ERROR);
return false;
}
diff --git a/lib/private/user/session.php b/lib/private/user/session.php
index ba702c9f365..be38b1b1d8e 100644
--- a/lib/private/user/session.php
+++ b/lib/private/user/session.php
@@ -213,6 +213,7 @@ class Session implements IUserSession, Emitter {
* @throws LoginException
*/
public function login($uid, $password) {
+ $this->session->regenerateId();
$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
$user = $this->manager->checkPassword($uid, $password);
if ($user !== false) {
@@ -243,6 +244,7 @@ class Session implements IUserSession, Emitter {
* @return bool
*/
public function loginWithCookie($uid, $currentToken) {
+ $this->session->regenerateId();
$this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
$user = $this->manager->get($uid);
if (is_null($user)) {
diff --git a/lib/private/util.php b/lib/private/util.php
index 9016dc59751..6a9980fc129 100644
--- a/lib/private/util.php
+++ b/lib/private/util.php
@@ -72,7 +72,7 @@ class OC_Util {
private static function initLocalStorageRootFS() {
// mount local file backend as root
- $configDataDirectory = OC_Config::getValue("datadirectory", OC::$SERVERROOT . "/data");
+ $configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
//first set up the local "root" storage
\OC\Files\Filesystem::initMountManager();
if (!self::$rootMounted) {
@@ -184,7 +184,7 @@ class OC_Util {
OC_Hook::emit('OC_Filesystem', 'preSetup', array('user' => $user));
//check if we are using an object storage
- $objectStore = OC_Config::getValue('objectstore');
+ $objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
if (isset($objectStore)) {
self::initObjectStoreRootFS($objectStore);
} else {
@@ -848,7 +848,7 @@ class OC_Util {
public static function checkDatabaseVersion() {
$l = \OC::$server->getL10N('lib');
$errors = array();
- $dbType = \OC_Config::getValue('dbtype', 'sqlite');
+ $dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
if ($dbType === 'pgsql') {
// check PostgreSQL version
try {
@@ -951,9 +951,11 @@ class OC_Util {
$parameters['canResetPassword'] = true;
if (!\OC::$server->getSystemConfig()->getValue('lost_password_link')) {
- $user = \OC::$server->getUserManager()->get($_REQUEST['user']);
- if ($user instanceof IUser) {
- $parameters['canResetPassword'] = $user->canChangePassword();
+ if (isset($_REQUEST['user'])) {
+ $user = \OC::$server->getUserManager()->get($_REQUEST['user']);
+ if ($user instanceof IUser) {
+ $parameters['canResetPassword'] = $user->canChangePassword();
+ }
}
}
@@ -972,7 +974,7 @@ class OC_Util {
*/
public static function checkAppEnabled($app) {
if (!OC_App::isEnabled($app)) {
- header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
+ header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
exit();
}
}
@@ -986,7 +988,7 @@ class OC_Util {
public static function checkLoggedIn() {
// Check if we are a user
if (!OC_User::isLoggedIn()) {
- header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php',
+ header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php',
[
'redirect_url' => \OC::$server->getRequest()->getRequestUri()
]
@@ -1004,7 +1006,7 @@ class OC_Util {
public static function checkAdminUser() {
OC_Util::checkLoggedIn();
if (!OC_User::isAdminUser(OC_User::getUser())) {
- header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
+ header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
exit();
}
}
@@ -1044,7 +1046,7 @@ class OC_Util {
}
if (!$isSubAdmin) {
- header('Location: ' . OC_Helper::linkToAbsolute('', 'index.php'));
+ header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
exit();
}
return true;
@@ -1106,11 +1108,11 @@ class OC_Util {
* @return string
*/
public static function getInstanceId() {
- $id = OC_Config::getValue('instanceid', null);
+ $id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
if (is_null($id)) {
// We need to guarantee at least one letter in instanceid so it can be used as the session_name
$id = 'oc' . \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
- OC_Config::$object->setValue('instanceid', $id);
+ \OC::$server->getSystemConfig()->setValue('instanceid', $id);
}
return $id;
}
@@ -1125,7 +1127,6 @@ class OC_Util {
* Creates a 'request token' (random) and stores it inside the session.
* Ever subsequent (ajax) request must use such a valid token to succeed,
* otherwise the request will be denied as a protection against CSRF.
- * @see OC_Util::isCallRegistered()
*/
public static function callRegister() {
// Use existing token if function has already been called
@@ -1153,27 +1154,6 @@ class OC_Util {
}
/**
- * Check an ajax get/post call if the request token is valid.
- *
- * @return boolean False if request token is not set or is invalid.
- * @see OC_Util::callRegister()
- */
- public static function isCallRegistered() {
- return \OC::$server->getRequest()->passesCSRFCheck();
- }
-
- /**
- * Check an ajax get/post call if the request token is valid. Exit if not.
- *
- * @return void
- */
- public static function callCheck() {
- if (!OC_Util::isCallRegistered()) {
- exit();
- }
- }
-
- /**
* Public function to sanitize HTML
*
* This function is used to sanitize HTML and should be applied on any
@@ -1248,7 +1228,7 @@ class OC_Util {
fclose($fp);
// accessing the file via http
- $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT . '/data' . $fileName);
+ $url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
try {
$content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
} catch (\Exception $e) {
@@ -1362,7 +1342,7 @@ class OC_Util {
* @return string the theme
*/
public static function getTheme() {
- $theme = OC_Config::getValue("theme", '');
+ $theme = \OC::$server->getSystemConfig()->getValue("theme", '');
if ($theme === '') {
if (is_dir(OC::$SERVERROOT . '/themes/default')) {
@@ -1503,14 +1483,28 @@ class OC_Util {
*
* @param \OCP\IConfig $config
* @return bool whether the core or any app needs an upgrade
+ * @throws \OC\HintException When the upgrade from the given version is not allowed
*/
public static function needUpgrade(\OCP\IConfig $config) {
if ($config->getSystemValue('installed', false)) {
$installedVersion = $config->getSystemValue('version', '0.0.0');
- $currentVersion = implode('.', OC_Util::getVersion());
+ $currentVersion = implode('.', \OCP\Util::getVersion());
$versionDiff = version_compare($currentVersion, $installedVersion);
if ($versionDiff > 0) {
return true;
+ } else if ($config->getSystemValue('debug', false) && $versionDiff < 0) {
+ // downgrade with debug
+ $installedMajor = explode('.', $installedVersion);
+ $installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
+ $currentMajor = explode('.', $currentVersion);
+ $currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
+ if ($installedMajor === $currentMajor) {
+ // Same major, allow downgrade for developers
+ return true;
+ } else {
+ // downgrade attempt, throw exception
+ throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
+ }
} else if ($versionDiff < 0) {
// downgrade attempt, throw exception
throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');