summaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/app.php37
-rw-r--r--lib/private/app/appmanager.php7
-rw-r--r--lib/private/app/infoparser.php2
-rw-r--r--lib/private/appframework/app.php2
-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/simplecontainer.php2
-rw-r--r--lib/private/apphelper.php8
-rw-r--r--lib/private/comments/comment.php357
-rw-r--r--lib/private/comments/manager.php549
-rw-r--r--lib/private/comments/managerfactory.php23
-rw-r--r--lib/private/console/application.php21
-rw-r--r--lib/private/db/querybuilder/querybuilder.php76
-rw-r--r--lib/private/db/querybuilder/quotehelper.php2
-rw-r--r--lib/private/files.php2
-rw-r--r--lib/private/files/fileinfo.php8
-rw-r--r--lib/private/files/filesystem.php1
-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/wrapper/availability.php1
-rw-r--r--lib/private/files/view.php10
-rw-r--r--lib/private/helper.php12
-rw-r--r--lib/private/l10n.php10
-rw-r--r--lib/private/lock/abstractlockingprovider.php2
-rw-r--r--lib/private/lock/dblockingprovider.php8
-rw-r--r--lib/private/lock/memcachelockingprovider.php9
-rw-r--r--lib/private/log.php2
-rw-r--r--lib/private/memcache/apc.php4
-rw-r--r--lib/private/memcache/apcu.php4
-rw-r--r--lib/private/memcache/redis.php8
-rw-r--r--lib/private/memcache/xcache.php4
-rw-r--r--lib/private/preview.php8
-rw-r--r--lib/private/repair.php7
-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/security/trusteddomainhelper.php7
-rw-r--r--lib/private/server.php14
-rw-r--r--lib/private/session/cryptowrapper.php1
-rw-r--r--lib/private/setup.php36
-rw-r--r--lib/private/setup/mysql.php25
-rw-r--r--lib/private/share/mailnotifications.php10
-rw-r--r--lib/private/share/share.php13
-rw-r--r--lib/private/systemtag/systemtagmanager.php4
-rw-r--r--lib/private/systemtag/systemtagobjectmapper.php6
-rw-r--r--lib/private/template.php6
-rw-r--r--lib/private/template/functions.php4
-rw-r--r--lib/private/tempmanager.php2
-rw-r--r--lib/private/user/user.php2
-rw-r--r--lib/private/util.php59
51 files changed, 1234 insertions, 279 deletions
diff --git a/lib/private/app.php b/lib/private/app.php
index c6e235eda4d..abf12264c58 100644
--- a/lib/private/app.php
+++ b/lib/private/app.php
@@ -361,37 +361,6 @@ class OC_App {
}
/**
- * marks a navigation entry as active
- *
- * @param string $id id of the entry
- * @return bool
- *
- * This function sets a navigation entry as active and removes the 'active'
- * property from all other entries. The templates can use this for
- * highlighting the current position of the user.
- *
- * @deprecated Use \OC::$server->getNavigationManager()->setActiveEntry() instead
- */
- public static function setActiveNavigationEntry($id) {
- OC::$server->getNavigationManager()->setActiveEntry($id);
- return true;
- }
-
- /**
- * gets the active Menu entry
- *
- * @return string id or empty string
- *
- * This function returns the id of the active navigation entry (set by
- * setActiveNavigationEntry
- *
- * @deprecated Use \OC::$server->getNavigationManager()->getActiveEntry() instead
- */
- public static function getActiveNavigationEntry() {
- return OC::$server->getNavigationManager()->getActiveEntry();
- }
-
- /**
* Returns the Settings Navigation
*
* @return string[]
@@ -505,9 +474,13 @@ class OC_App {
* search for an app in all app-directories
*
* @param string $appId
- * @return mixed (bool|string)
+ * @return false|string
*/
protected static function findAppInDirectories($appId) {
+ $sanitizedAppId = self::cleanAppId($appId);
+ if($sanitizedAppId !== $appId) {
+ return false;
+ }
static $app_dir = array();
if (isset($app_dir[$appId])) {
diff --git a/lib/private/app/appmanager.php b/lib/private/app/appmanager.php
index f826c8ba0c7..8ae93f98832 100644
--- a/lib/private/app/appmanager.php
+++ b/lib/private/app/appmanager.php
@@ -148,6 +148,13 @@ class AppManager implements IAppManager {
return false;
} else {
$groupIds = json_decode($enabled);
+
+ if (!is_array($groupIds)) {
+ $jsonError = json_last_error();
+ \OC::$server->getLogger()->warning('AppManger::checkAppForUser - can\'t decode group IDs: ' . print_r($enabled, true) . ' - json error code: ' . $jsonError, ['app' => 'lib']);
+ return false;
+ }
+
$userGroups = $this->groupManager->getUserGroupIds($user);
foreach ($userGroups as $groupId) {
if (array_search($groupId, $groupIds) !== false) {
diff --git a/lib/private/app/infoparser.php b/lib/private/app/infoparser.php
index 789f01e5bc4..22f705884bc 100644
--- a/lib/private/app/infoparser.php
+++ b/lib/private/app/infoparser.php
@@ -61,7 +61,7 @@ class InfoParser {
if ($xml == false) {
return null;
}
- $array = $this->xmlToArray($xml, false);
+ $array = $this->xmlToArray($xml);
if (is_null($array)) {
return null;
}
diff --git a/lib/private/appframework/app.php b/lib/private/appframework/app.php
index 0188d221be1..5cad32bbd09 100644
--- a/lib/private/appframework/app.php
+++ b/lib/private/appframework/app.php
@@ -26,6 +26,7 @@
namespace OC\AppFramework;
+use OC\AppFramework\Http\Dispatcher;
use OC_App;
use OC\AppFramework\DependencyInjection\DIContainer;
use OCP\AppFramework\QueryException;
@@ -97,6 +98,7 @@ class App {
}
// initialize the dispatcher and run all the middleware before the controller
+ /** @var Dispatcher $dispatcher */
$dispatcher = $container['Dispatcher'];
list(
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/simplecontainer.php b/lib/private/appframework/utility/simplecontainer.php
index bcae351e023..e55d4e20a81 100644
--- a/lib/private/appframework/utility/simplecontainer.php
+++ b/lib/private/appframework/utility/simplecontainer.php
@@ -29,9 +29,7 @@ namespace OC\AppFramework\Utility;
use ReflectionClass;
use ReflectionException;
use Closure;
-
use Pimple\Container;
-
use OCP\AppFramework\QueryException;
use OCP\IContainer;
diff --git a/lib/private/apphelper.php b/lib/private/apphelper.php
index 9084d2b8ab4..478787b21d8 100644
--- a/lib/private/apphelper.php
+++ b/lib/private/apphelper.php
@@ -36,6 +36,12 @@ class AppHelper implements \OCP\IHelper {
* @deprecated 8.1.0 Use \OCP\IServerContainer::getHTTPClientService
*/
public function getUrlContent($url) {
- return \OC_Util::getUrlContent($url);
+ try {
+ $client = \OC::$server->getHTTPClientService()->newClient();
+ $response = $client->get($url);
+ return $response->getBody();
+ } catch (\Exception $e) {
+ return false;
+ }
}
}
diff --git a/lib/private/comments/comment.php b/lib/private/comments/comment.php
new file mode 100644
index 00000000000..219e7ec8e4b
--- /dev/null
+++ b/lib/private/comments/comment.php
@@ -0,0 +1,357 @@
+<?php
+
+namespace OC\Comments;
+
+use OCP\Comments\IComment;
+use OCP\Comments\IllegalIDChangeException;
+
+class Comment implements IComment {
+
+ protected $data = [
+ 'id' => '',
+ 'parentId' => '0',
+ 'topmostParentId' => '0',
+ 'childrenCount' => '0',
+ 'message' => '',
+ 'verb' => '',
+ 'actorType' => '',
+ 'actorId' => '',
+ 'objectType' => '',
+ 'objectId' => '',
+ 'creationDT' => null,
+ 'latestChildDT' => null,
+ ];
+
+ /**
+ * Comment constructor.
+ *
+ * @param [] $data optional, array with keys according to column names from
+ * the comments database scheme
+ */
+ public function __construct(array $data = null) {
+ if(is_array($data)) {
+ $this->fromArray($data);
+ }
+ }
+
+ /**
+ * returns the ID of the comment
+ *
+ * It may return an empty string, if the comment was not stored.
+ * It is expected that the concrete Comment implementation gives an ID
+ * by itself (e.g. after saving).
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getId() {
+ return $this->data['id'];
+ }
+
+ /**
+ * sets the ID of the comment and returns itself
+ *
+ * It is only allowed to set the ID only, if the current id is an empty
+ * string (which means it is not stored in a database, storage or whatever
+ * the concrete implementation does), or vice versa. Changing a given ID is
+ * not permitted and must result in an IllegalIDChangeException.
+ *
+ * @param string $id
+ * @return IComment
+ * @throws IllegalIDChangeException
+ * @since 9.0.0
+ */
+ public function setId($id) {
+ if(!is_string($id)) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+
+ $id = trim($id);
+ if($this->data['id'] === '' || ($this->data['id'] !== '' && $id === '')) {
+ $this->data['id'] = $id;
+ return $this;
+ }
+
+ throw new IllegalIDChangeException('Not allowed to assign a new ID to an already saved comment.');
+ }
+
+ /**
+ * returns the parent ID of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getParentId() {
+ return $this->data['parentId'];
+ }
+
+ /**
+ * sets the parent ID and returns itself
+ *
+ * @param string $parentId
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setParentId($parentId) {
+ if(!is_string($parentId)) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['parentId'] = trim($parentId);
+ return $this;
+ }
+
+ /**
+ * returns the topmost parent ID of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getTopmostParentId() {
+ return $this->data['topmostParentId'];
+ }
+
+
+ /**
+ * sets the topmost parent ID and returns itself
+ *
+ * @param string $id
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setTopmostParentId($id) {
+ if(!is_string($id)) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['topmostParentId'] = trim($id);
+ return $this;
+ }
+
+ /**
+ * returns the number of children
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getChildrenCount() {
+ return $this->data['childrenCount'];
+ }
+
+ /**
+ * sets the number of children
+ *
+ * @param int $count
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setChildrenCount($count) {
+ if(!is_int($count)) {
+ throw new \InvalidArgumentException('Integer expected.');
+ }
+ $this->data['childrenCount'] = $count;
+ return $this;
+ }
+
+ /**
+ * returns the message of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getMessage() {
+ return $this->data['message'];
+ }
+
+ /**
+ * sets the message of the comment and returns itself
+ *
+ * @param string $message
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setMessage($message) {
+ if(!is_string($message)) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['message'] = trim($message);
+ return $this;
+ }
+
+ /**
+ * returns the verb of the comment
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getVerb() {
+ return $this->data['verb'];
+ }
+
+ /**
+ * sets the verb of the comment, e.g. 'comment' or 'like'
+ *
+ * @param string $verb
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setVerb($verb) {
+ if(!is_string($verb) || !trim($verb)) {
+ throw new \InvalidArgumentException('Non-empty String expected.');
+ }
+ $this->data['verb'] = trim($verb);
+ return $this;
+ }
+
+ /**
+ * returns the actor type
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getActorType() {
+ return $this->data['actorType'];
+ }
+
+ /**
+ * returns the actor ID
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getActorId() {
+ return $this->data['actorId'];
+ }
+
+ /**
+ * sets (overwrites) the actor type and id
+ *
+ * @param string $actorType e.g. 'user'
+ * @param string $actorId e.g. 'zombie234'
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setActor($actorType, $actorId) {
+ if(
+ !is_string($actorType) || !trim($actorType)
+ || !is_string($actorId) || !trim($actorId)
+ ) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['actorType'] = trim($actorType);
+ $this->data['actorId'] = trim($actorId);
+ return $this;
+ }
+
+ /**
+ * returns the creation date of the comment.
+ *
+ * If not explicitly set, it shall default to the time of initialization.
+ *
+ * @return \DateTime
+ * @since 9.0.0
+ */
+ public function getCreationDateTime() {
+ return $this->data['creationDT'];
+ }
+
+ /**
+ * sets the creation date of the comment and returns itself
+ *
+ * @param \DateTime $timestamp
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setCreationDateTime(\DateTime $timestamp) {
+ $this->data['creationDT'] = $timestamp;
+ return $this;
+ }
+
+ /**
+ * returns the timestamp of the most recent child
+ *
+ * @return int
+ * @since 9.0.0
+ */
+ public function getLatestChildDateTime() {
+ return $this->data['latestChildDT'];
+ }
+
+ /**
+ * sets the date of the most recent child
+ *
+ * @param \DateTime $dateTime
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setLatestChildDateTime(\DateTime $dateTime = null) {
+ $this->data['latestChildDT'] = $dateTime;
+ return $this;
+ }
+
+ /**
+ * returns the object type the comment is attached to
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getObjectType() {
+ return $this->data['objectType'];
+ }
+
+ /**
+ * returns the object id the comment is attached to
+ *
+ * @return string
+ * @since 9.0.0
+ */
+ public function getObjectId() {
+ return $this->data['objectId'];
+ }
+
+ /**
+ * sets (overwrites) the object of the comment
+ *
+ * @param string $objectType e.g. 'file'
+ * @param string $objectId e.g. '16435'
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function setObject($objectType, $objectId) {
+ if(
+ !is_string($objectType) || !trim($objectType)
+ || !is_string($objectId) || !trim($objectId)
+ ) {
+ throw new \InvalidArgumentException('String expected.');
+ }
+ $this->data['objectType'] = trim($objectType);
+ $this->data['objectId'] = trim($objectId);
+ return $this;
+ }
+
+ /**
+ * sets the comment data based on an array with keys as taken from the
+ * database.
+ *
+ * @param [] $data
+ * @return IComment
+ */
+ protected function fromArray($data) {
+ foreach(array_keys($data) as $key) {
+ // translate DB keys to internal setter names
+ $setter = 'set' . str_replace('_', '', ucwords($key,'_'));
+ $setter = str_replace('Timestamp', 'DateTime', $setter);
+
+ if(method_exists($this, $setter)) {
+ $this->$setter($data[$key]);
+ }
+ }
+
+ foreach(['actor', 'object'] as $role) {
+ if(isset($data[$role . '_type']) && isset($data[$role . '_id'])) {
+ $setter = 'set' . ucfirst($role);
+ $this->$setter($data[$role . '_type'], $data[$role . '_id']);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/lib/private/comments/manager.php b/lib/private/comments/manager.php
new file mode 100644
index 00000000000..09e59f28370
--- /dev/null
+++ b/lib/private/comments/manager.php
@@ -0,0 +1,549 @@
+<?php
+
+namespace OC\Comments;
+
+use Doctrine\DBAL\Exception\DriverException;
+use OCP\Comments\IComment;
+use OCP\Comments\ICommentsManager;
+use OCP\Comments\NotFoundException;
+use OCP\IDBConnection;
+use OCP\ILogger;
+
+class Manager implements ICommentsManager {
+
+ /** @var IDBConnection */
+ protected $dbConn;
+
+ /** @var ILogger */
+ protected $logger;
+
+ /** @var IComment[] */
+ protected $commentsCache = [];
+
+ public function __construct(
+ IDBConnection $dbConn,
+ ILogger $logger
+ ) {
+ $this->dbConn = $dbConn;
+ $this->logger = $logger;
+ }
+
+ /**
+ * converts data base data into PHP native, proper types as defined by
+ * IComment interface.
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function normalizeDatabaseData(array $data) {
+ $data['id'] = strval($data['id']);
+ $data['parent_id'] = strval($data['parent_id']);
+ $data['topmost_parent_id'] = strval($data['topmost_parent_id']);
+ $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']);
+ $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']);
+ $data['children_count'] = intval($data['children_count']);
+ return $data;
+ }
+
+ /**
+ * prepares a comment for an insert or update operation after making sure
+ * all necessary fields have a value assigned.
+ *
+ * @param IComment $comment
+ * @return IComment returns the same updated IComment instance as provided
+ * by parameter for convenience
+ * @throws \UnexpectedValueException
+ */
+ protected function prepareCommentForDatabaseWrite(IComment $comment) {
+ if( !$comment->getActorType()
+ || !$comment->getActorId()
+ || !$comment->getObjectType()
+ || !$comment->getObjectId()
+ || !$comment->getVerb()
+ ) {
+ throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
+ }
+
+ if($comment->getId() === '') {
+ $comment->setChildrenCount(0);
+ $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC')));
+ $comment->setLatestChildDateTime(null);
+ }
+
+ if(is_null($comment->getCreationDateTime())) {
+ $comment->setCreationDateTime(new \DateTime());
+ }
+
+ if($comment->getParentId() !== '0') {
+ $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId()));
+ } else {
+ $comment->setTopmostParentId('0');
+ }
+
+ $this->cache($comment);
+
+ return $comment;
+ }
+
+ /**
+ * returns the topmost parent id of a given comment identified by ID
+ *
+ * @param string $id
+ * @return string
+ * @throws NotFoundException
+ */
+ protected function determineTopmostParentId($id) {
+ $comment = $this->get($id);
+ if($comment->getParentId() === '0') {
+ return $comment->getId();
+ } else {
+ return $this->determineTopmostParentId($comment->getId());
+ }
+ }
+
+ /**
+ * updates child information of a comment
+ *
+ * @param string $id
+ * @param \DateTime $cDateTime the date time of the most recent child
+ * @throws NotFoundException
+ */
+ protected function updateChildrenInformation($id, \DateTime $cDateTime) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->select($qb->createFunction('COUNT(`id`)'))
+ ->from('comments')
+ ->where($qb->expr()->eq('parent_id', $qb->createParameter('id')))
+ ->setParameter('id', $id);
+
+ $resultStatement = $query->execute();
+ $data = $resultStatement->fetch(\PDO::FETCH_NUM);
+ $resultStatement->closeCursor();
+ $children = intval($data[0]);
+
+ $comment = $this->get($id);
+ $comment->setChildrenCount($children);
+ $comment->setLatestChildDateTime($cDateTime);
+ $this->save($comment);
+ }
+
+ /**
+ * Tests whether actor or object type and id parameters are acceptable.
+ * Throws exception if not.
+ *
+ * @param string $role
+ * @param string $type
+ * @param string $id
+ * @throws \InvalidArgumentException
+ */
+ protected function checkRoleParameters($role, $type, $id) {
+ if(
+ !is_string($type) || empty($type)
+ || !is_string($id) || empty($id)
+ ) {
+ throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
+ }
+ }
+
+ /**
+ * run-time caches a comment
+ *
+ * @param IComment $comment
+ */
+ protected function cache(IComment $comment) {
+ $id = $comment->getId();
+ if(empty($id)) {
+ return;
+ }
+ $this->commentsCache[strval($id)] = $comment;
+ }
+
+ /**
+ * removes an entry from the comments run time cache
+ *
+ * @param mixed $id the comment's id
+ */
+ protected function uncache($id) {
+ $id = strval($id);
+ if (isset($this->commentsCache[$id])) {
+ unset($this->commentsCache[$id]);
+ }
+ }
+
+ /**
+ * returns a comment instance
+ *
+ * @param string $id the ID of the comment
+ * @return IComment
+ * @throws NotFoundException
+ * @throws \InvalidArgumentException
+ * @since 9.0.0
+ */
+ public function get($id) {
+ if(intval($id) === 0) {
+ throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.');
+ }
+
+ if(isset($this->commentsCache[$id])) {
+ return $this->commentsCache[$id];
+ }
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $resultStatement = $qb->select('*')
+ ->from('comments')
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter('id', $id, \PDO::PARAM_INT)
+ ->execute();
+
+ $data = $resultStatement->fetch();
+ $resultStatement->closeCursor();
+ if(!$data) {
+ throw new NotFoundException();
+ }
+
+ $comment = new Comment($this->normalizeDatabaseData($data));
+ $this->cache($comment);
+ return $comment;
+ }
+
+ /**
+ * returns the comment specified by the id and all it's child comments.
+ * At this point of time, we do only support one level depth.
+ *
+ * @param string $id
+ * @param int $limit max number of entries to return, 0 returns all
+ * @param int $offset the start entry
+ * @return array
+ * @since 9.0.0
+ *
+ * The return array looks like this
+ * [
+ * 'comment' => IComment, // root comment
+ * 'replies' =>
+ * [
+ * 0 =>
+ * [
+ * 'comment' => IComment,
+ * 'replies' => []
+ * ]
+ * 1 =>
+ * [
+ * 'comment' => IComment,
+ * 'replies'=> []
+ * ],
+ * …
+ * ]
+ * ]
+ */
+ public function getTree($id, $limit = 0, $offset = 0) {
+ $tree = [];
+ $tree['comment'] = $this->get($id);
+ $tree['replies'] = [];
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->select('*')
+ ->from('comments')
+ ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id')))
+ ->orderBy('creation_timestamp', 'DESC')
+ ->setParameter('id', $id);
+
+ if($limit > 0) {
+ $query->setMaxResults($limit);
+ }
+ if($offset > 0) {
+ $query->setFirstResult($offset);
+ }
+
+ $resultStatement = $query->execute();
+ while($data = $resultStatement->fetch()) {
+ $comment = new Comment($this->normalizeDatabaseData($data));
+ $this->cache($comment);
+ $tree['replies'][] = [
+ 'comment' => $comment,
+ 'replies' => []
+ ];
+ }
+ $resultStatement->closeCursor();
+
+ return $tree;
+ }
+
+ /**
+ * returns comments for a specific object (e.g. a file).
+ *
+ * The sort order is always newest to oldest.
+ *
+ * @param string $objectType the object type, e.g. 'files'
+ * @param string $objectId the id of the object
+ * @param int $limit optional, number of maximum comments to be returned. if
+ * not specified, all comments are returned.
+ * @param int $offset optional, starting point
+ * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
+ * that may be returned
+ * @return IComment[]
+ * @since 9.0.0
+ */
+ public function getForObject(
+ $objectType,
+ $objectId,
+ $limit = 0,
+ $offset = 0,
+ \DateTime $notOlderThan = null
+ ) {
+ $comments = [];
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->select('*')
+ ->from('comments')
+ ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
+ ->orderBy('creation_timestamp', 'DESC')
+ ->setParameter('type', $objectType)
+ ->setParameter('id', $objectId);
+
+ if($limit > 0) {
+ $query->setMaxResults($limit);
+ }
+ if($offset > 0) {
+ $query->setFirstResult($offset);
+ }
+ if(!is_null($notOlderThan)) {
+ $query
+ ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
+ ->setParameter('notOlderThan', $notOlderThan, 'datetime');
+ }
+
+ $resultStatement = $query->execute();
+ while($data = $resultStatement->fetch()) {
+ $comment = new Comment($this->normalizeDatabaseData($data));
+ $this->cache($comment);
+ $comments[] = $comment;
+ }
+ $resultStatement->closeCursor();
+
+ return $comments;
+ }
+
+ /**
+ * @param $objectType string the object type, e.g. 'files'
+ * @param $objectId string the id of the object
+ * @return Int
+ * @since 9.0.0
+ */
+ public function getNumberOfCommentsForObject($objectType, $objectId) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->select($qb->createFunction('COUNT(`id`)'))
+ ->from('comments')
+ ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
+ ->setParameter('type', $objectType)
+ ->setParameter('id', $objectId);
+
+ $resultStatement = $query->execute();
+ $data = $resultStatement->fetch(\PDO::FETCH_NUM);
+ $resultStatement->closeCursor();
+ return intval($data[0]);
+ }
+
+ /**
+ * creates a new comment and returns it. At this point of time, it is not
+ * saved in the used data storage. Use save() after setting other fields
+ * of the comment (e.g. message or verb).
+ *
+ * @param string $actorType the actor type (e.g. 'user')
+ * @param string $actorId a user id
+ * @param string $objectType the object type the comment is attached to
+ * @param string $objectId the object id the comment is attached to
+ * @return IComment
+ * @since 9.0.0
+ */
+ public function create($actorType, $actorId, $objectType, $objectId) {
+ $comment = new Comment();
+ $comment
+ ->setActor($actorType, $actorId)
+ ->setObject($objectType, $objectId);
+ return $comment;
+ }
+
+ /**
+ * permanently deletes the comment specified by the ID
+ *
+ * When the comment has child comments, their parent ID will be changed to
+ * the parent ID of the item that is to be deleted.
+ *
+ * @param string $id
+ * @return bool
+ * @throws \InvalidArgumentException
+ * @since 9.0.0
+ */
+ public function delete($id) {
+ if(!is_string($id)) {
+ throw new \InvalidArgumentException('Parameter must be string');
+ }
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $query = $qb->delete('comments')
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter('id', $id);
+
+ try {
+ $affectedRows = $query->execute();
+ $this->uncache($id);
+ } catch (DriverException $e) {
+ $this->logger->logException($e, ['app' => 'core_comments']);
+ return false;
+ }
+ return ($affectedRows > 0);
+ }
+
+ /**
+ * saves the comment permanently and returns it
+ *
+ * if the supplied comment has an empty ID, a new entry comment will be
+ * saved and the instance updated with the new ID.
+ *
+ * Otherwise, an existing comment will be updated.
+ *
+ * Throws NotFoundException when a comment that is to be updated does not
+ * exist anymore at this point of time.
+ *
+ * @param IComment $comment
+ * @return bool
+ * @throws NotFoundException
+ * @since 9.0.0
+ */
+ public function save(IComment $comment) {
+ if($this->prepareCommentForDatabaseWrite($comment)->getId() === '') {
+ $result = $this->insert($comment);
+ } else {
+ $result = $this->update($comment);
+ }
+
+ if($result && !!$comment->getParentId()) {
+ $this->updateChildrenInformation(
+ $comment->getParentId(),
+ $comment->getCreationDateTime()
+ );
+ $this->cache($comment);
+ }
+
+ return $result;
+ }
+
+ /**
+ * inserts the provided comment in the database
+ *
+ * @param IComment $comment
+ * @return bool
+ */
+ protected function insert(IComment &$comment) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $affectedRows = $qb
+ ->insert('comments')
+ ->values([
+ 'parent_id' => $qb->createNamedParameter($comment->getParentId()),
+ 'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()),
+ 'children_count' => $qb->createNamedParameter($comment->getChildrenCount()),
+ 'actor_type' => $qb->createNamedParameter($comment->getActorType()),
+ 'actor_id' => $qb->createNamedParameter($comment->getActorId()),
+ 'message' => $qb->createNamedParameter($comment->getMessage()),
+ 'verb' => $qb->createNamedParameter($comment->getVerb()),
+ 'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'),
+ 'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'),
+ 'object_type' => $qb->createNamedParameter($comment->getObjectType()),
+ 'object_id' => $qb->createNamedParameter($comment->getObjectId()),
+ ])
+ ->execute();
+
+ if ($affectedRows > 0) {
+ $comment->setId(strval($qb->getLastInsertId()));
+ }
+
+ return $affectedRows > 0;
+ }
+
+ /**
+ * updates a Comment data row
+ *
+ * @param IComment $comment
+ * @return bool
+ * @throws NotFoundException
+ */
+ protected function update(IComment $comment) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $affectedRows = $qb
+ ->update('comments')
+ ->set('parent_id', $qb->createNamedParameter($comment->getParentId()))
+ ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId()))
+ ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount()))
+ ->set('actor_type', $qb->createNamedParameter($comment->getActorType()))
+ ->set('actor_id', $qb->createNamedParameter($comment->getActorId()))
+ ->set('message', $qb->createNamedParameter($comment->getMessage()))
+ ->set('verb', $qb->createNamedParameter($comment->getVerb()))
+ ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'))
+ ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'))
+ ->set('object_type', $qb->createNamedParameter($comment->getObjectType()))
+ ->set('object_id', $qb->createNamedParameter($comment->getObjectId()))
+ ->where($qb->expr()->eq('id', $qb->createParameter('id')))
+ ->setParameter('id', $comment->getId())
+ ->execute();
+
+ if($affectedRows === 0) {
+ throw new NotFoundException('Comment to update does ceased to exist');
+ }
+
+ return $affectedRows > 0;
+ }
+
+ /**
+ * removes references to specific actor (e.g. on user delete) of a comment.
+ * The comment itself must not get lost/deleted.
+ *
+ * @param string $actorType the actor type (e.g. 'user')
+ * @param string $actorId a user id
+ * @return boolean
+ * @since 9.0.0
+ */
+ public function deleteReferencesOfActor($actorType, $actorId) {
+ $this->checkRoleParameters('Actor', $actorType, $actorId);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $affectedRows = $qb
+ ->update('comments')
+ ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
+ ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
+ ->where($qb->expr()->eq('actor_type', $qb->createParameter('type')))
+ ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id')))
+ ->setParameter('type', $actorType)
+ ->setParameter('id', $actorId)
+ ->execute();
+
+ $this->commentsCache = [];
+
+ return is_int($affectedRows);
+ }
+
+ /**
+ * deletes all comments made of a specific object (e.g. on file delete)
+ *
+ * @param string $objectType the object type (e.g. 'file')
+ * @param string $objectId e.g. the file id
+ * @return boolean
+ * @since 9.0.0
+ */
+ public function deleteCommentsAtObject($objectType, $objectId) {
+ $this->checkRoleParameters('Object', $objectType, $objectId);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $affectedRows = $qb
+ ->delete('comments')
+ ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
+ ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
+ ->setParameter('type', $objectType)
+ ->setParameter('id', $objectId)
+ ->execute();
+
+ $this->commentsCache = [];
+
+ return is_int($affectedRows);
+ }
+}
diff --git a/lib/private/comments/managerfactory.php b/lib/private/comments/managerfactory.php
new file mode 100644
index 00000000000..41978d0cf4b
--- /dev/null
+++ b/lib/private/comments/managerfactory.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace OC\Comments;
+
+use OCP\Comments\ICommentsManager;
+use OCP\Comments\ICommentsManagerFactory;
+
+
+class ManagerFactory implements ICommentsManagerFactory {
+
+ /**
+ * creates and returns an instance of the ICommentsManager
+ *
+ * @return ICommentsManager
+ * @since 9.0.0
+ */
+ public function getManager() {
+ return new Manager(
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->getLogger()
+ );
+ }
+}
diff --git a/lib/private/console/application.php b/lib/private/console/application.php
index 55c817d497f..e6d8677b72e 100644
--- a/lib/private/console/application.php
+++ b/lib/private/console/application.php
@@ -48,25 +48,31 @@ class Application {
/**
* @param OutputInterface $output
+ * @throws \Exception
*/
public function loadCommands(OutputInterface $output) {
// $application is required to be defined in the register_command scripts
$application = $this->application;
- require_once \OC::$SERVERROOT . '/core/register_command.php';
+ require_once __DIR__ . '/../../../core/register_command.php';
if ($this->config->getSystemValue('installed', false)) {
- if (!\OCP\Util::needUpgrade()) {
+ if (\OCP\Util::needUpgrade()) {
+ $output->writeln("ownCloud or one of the apps require upgrade - only a limited number of commands are available");
+ $output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
+ } elseif ($this->config->getSystemValue('maintenance', false)) {
+ $output->writeln("ownCloud is in maintenance mode - no app have been loaded");
+ } else {
OC_App::loadApps();
foreach (\OC::$server->getAppManager()->getInstalledApps() as $app) {
$appPath = \OC_App::getAppPath($app);
+ if($appPath === false) {
+ continue;
+ }
\OC::$loader->addValidRoot($appPath);
$file = $appPath . '/appinfo/register_command.php';
if (file_exists($file)) {
require $file;
}
}
- } else {
- $output->writeln("ownCloud or one of the apps require upgrade - only a limited number of commands are available");
- $output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
}
} else {
$output->writeln("ownCloud is not installed - only a limited number of commands are available");
@@ -85,6 +91,11 @@ class Application {
}
}
+ /**
+ * Sets whether to automatically exit after a command execution or not.
+ *
+ * @param bool $boolean Whether to automatically exit after a command execution or not
+ */
public function setAutoExit($boolean) {
$this->application->setAutoExit($boolean);
}
diff --git a/lib/private/db/querybuilder/querybuilder.php b/lib/private/db/querybuilder/querybuilder.php
index 02d8ee4344d..a4cbb5abd76 100644
--- a/lib/private/db/querybuilder/querybuilder.php
+++ b/lib/private/db/querybuilder/querybuilder.php
@@ -40,6 +40,9 @@ class QueryBuilder implements IQueryBuilder {
/** @var bool */
private $automaticTablePrefix = true;
+ /** @var string */
+ protected $lastInsertedTable;
+
/**
* Initializes a new QueryBuilder.
*
@@ -325,6 +328,28 @@ class QueryBuilder implements IQueryBuilder {
}
/**
+ * Specifies an item that is to be returned uniquely in the query result.
+ *
+ * <code>
+ * $qb = $conn->getQueryBuilder()
+ * ->selectDistinct('type')
+ * ->from('users');
+ * </code>
+ *
+ * @param mixed $select The selection expressions.
+ *
+ * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+ */
+ public function selectDistinct($select) {
+
+ $this->queryBuilder->addSelect(
+ 'DISTINCT ' . $this->helper->quoteColumnName($select)
+ );
+
+ return $this;
+ }
+
+ /**
* Adds an item that is to be returned in the query result.
*
* <code>
@@ -423,6 +448,8 @@ class QueryBuilder implements IQueryBuilder {
$this->getTableName($insert)
);
+ $this->lastInsertedTable = $insert;
+
return $this;
}
@@ -1024,14 +1051,57 @@ class QueryBuilder implements IQueryBuilder {
}
/**
+ * Used to get the id of the last inserted element
+ * @return int
+ * @throws \BadMethodCallException When being called before an insert query has been run.
+ */
+ public function getLastInsertId() {
+ if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && $this->lastInsertedTable) {
+ // lastInsertId() needs the prefix but no quotes
+ $table = $this->prefixTableName($this->lastInsertedTable);
+ return (int) $this->connection->lastInsertId($table);
+ }
+
+ throw new \BadMethodCallException('Invalid call to getLastInsertId without using insert() before.');
+ }
+
+ /**
+ * Returns the table name quoted and with database prefix as needed by the implementation
+ *
+ * @param string $table
+ * @return string
+ */
+ public function getTableName($table) {
+ $table = $this->prefixTableName($table);
+ return $this->helper->quoteColumnName($table);
+ }
+
+ /**
+ * Returns the table name with database prefix as needed by the implementation
+ *
* @param string $table
* @return string
*/
- private function getTableName($table) {
+ protected function prefixTableName($table) {
if ($this->automaticTablePrefix === false || strpos($table, '*PREFIX*') === 0) {
- return $this->helper->quoteColumnName($table);
+ return $table;
+ }
+
+ return '*PREFIX*' . $table;
+ }
+
+ /**
+ * Returns the column name quoted and with table alias prefix as needed by the implementation
+ *
+ * @param string $column
+ * @param string $tableAlias
+ * @return string
+ */
+ public function getColumnName($column, $tableAlias = '') {
+ if ($tableAlias !== '') {
+ $tableAlias .= '.';
}
- return $this->helper->quoteColumnName('*PREFIX*' . $table);
+ return $this->helper->quoteColumnName($tableAlias . $column);
}
}
diff --git a/lib/private/db/querybuilder/quotehelper.php b/lib/private/db/querybuilder/quotehelper.php
index 4b62fee6a6c..5ceb76bbf93 100644
--- a/lib/private/db/querybuilder/quotehelper.php
+++ b/lib/private/db/querybuilder/quotehelper.php
@@ -61,7 +61,7 @@ class QuoteHelper {
}
if (substr_count($string, '.')) {
- list($alias, $columnName) = explode('.', $string);
+ list($alias, $columnName) = explode('.', $string, 2);
if ($columnName === '*') {
return $string;
diff --git a/lib/private/files.php b/lib/private/files.php
index af10f3e1e32..1cda28496cb 100644
--- a/lib/private/files.php
+++ b/lib/private/files.php
@@ -115,7 +115,7 @@ class OC_Files {
self::lockFiles($view, $dir, $files);
$streamer->sendHeaders($name);
- $executionTime = intval(ini_get('max_execution_time'));
+ $executionTime = intval(OC::$server->getIniWrapper()->getNumeric('max_execution_time'));
set_time_limit(0);
if ($getType === self::ZIP_FILES) {
foreach ($files as $file) {
diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php
index 5b5e8697004..5ed65cd3795 100644
--- a/lib/private/files/fileinfo.php
+++ b/lib/private/files/fileinfo.php
@@ -100,6 +100,8 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
return $this->getType();
} else if ($offset === 'etag') {
return $this->getEtag();
+ } elseif ($offset === 'permissions') {
+ return $this->getPermissions();
} elseif (isset($this->data[$offset])) {
return $this->data[$offset];
} else {
@@ -193,7 +195,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* @return int
*/
public function getPermissions() {
- return $this->data['permissions'];
+ $perms = $this->data['permissions'];
+ if (\OCP\Util::isSharingDisabledForUser() || ($this->isShared() && !\OC\Share\Share::isResharingAllowed())) {
+ $perms = $perms & ~\OCP\Constants::PERMISSION_SHARE;
+ }
+ return $perms;
}
/**
diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php
index 9f243c15a4c..9d1b7150687 100644
--- a/lib/private/files/filesystem.php
+++ b/lib/private/files/filesystem.php
@@ -58,7 +58,6 @@
namespace OC\Files;
-use OC\Cache\File;
use OC\Files\Config\MountProviderCollection;
use OC\Files\Storage\StorageFactory;
use OCP\Files\Config\IMountProvider;
diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php
index 0cd67e343ff..b06543d0a6a 100644
--- a/lib/private/files/storage/common.php
+++ b/lib/private/files/storage/common.php
@@ -141,10 +141,6 @@ abstract class Common implements Storage {
}
public function isSharable($path) {
- if (\OCP\Util::isSharingDisabledForUser()) {
- return false;
- }
-
return $this->isReadable($path);
}
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/wrapper/availability.php b/lib/private/files/storage/wrapper/availability.php
index d6ce78f6e44..d2fbbbacf75 100644
--- a/lib/private/files/storage/wrapper/availability.php
+++ b/lib/private/files/storage/wrapper/availability.php
@@ -399,7 +399,6 @@ class Availability extends Wrapper {
/** {@inheritdoc} */
public function getOwner($path) {
- $this->checkAvailability();
try {
return parent::getOwner($path);
} catch (\OCP\Files\StorageNotAvailableException $e) {
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index 7854790d0e5..b8b1b8a50d6 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -1253,7 +1253,7 @@ class View {
* @param boolean|string $includeMountPoints true to add mountpoint sizes,
* 'ext' to add only ext storage mount point sizes. Defaults to true.
* defaults to true
- * @return \OC\Files\FileInfo|bool False if file does not exist
+ * @return \OC\Files\FileInfo|false False if file does not exist
*/
public function getFileInfo($path, $includeMountPoints = true) {
$this->assertPathLength($path);
@@ -1427,13 +1427,9 @@ class View {
if ($mimetype_filter) {
$files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
if (strpos($mimetype_filter, '/')) {
- if ($file->getMimetype() === $mimetype_filter) {
- $result[] = $file;
- }
+ return $file->getMimetype() === $mimetype_filter;
} else {
- if ($file->getMimePart() === $mimetype_filter) {
- $result[] = $file;
- }
+ return $file->getMimePart() === $mimetype_filter;
}
});
}
diff --git a/lib/private/helper.php b/lib/private/helper.php
index 3cad77e6667..78a567638ef 100644
--- a/lib/private/helper.php
+++ b/lib/private/helper.php
@@ -441,7 +441,7 @@ class OC_Helper {
// Default check will be done with $path directories :
$dirs = explode(PATH_SEPARATOR, $path);
// WARNING : We have to check if open_basedir is enabled :
- $obd = ini_get('open_basedir');
+ $obd = OC::$server->getIniWrapper()->getString('open_basedir');
if ($obd != "none") {
$obd_values = explode(PATH_SEPARATOR, $obd);
if (count($obd_values) > 0 and $obd_values[0]) {
@@ -701,8 +701,9 @@ class OC_Helper {
* @return int PHP upload file size limit
*/
public static function uploadLimit() {
- $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize'));
- $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size'));
+ $ini = \OC::$server->getIniWrapper();
+ $upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize'));
+ $post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size'));
if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
return INF;
} elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
@@ -722,12 +723,13 @@ class OC_Helper {
if (!function_exists($function_name)) {
return false;
}
- $disabled = explode(',', ini_get('disable_functions'));
+ $ini = \OC::$server->getIniWrapper();
+ $disabled = explode(',', $ini->get('disable_functions'));
$disabled = array_map('trim', $disabled);
if (in_array($function_name, $disabled)) {
return false;
}
- $disabled = explode(',', ini_get('suhosin.executor.func.blacklist'));
+ $disabled = explode(',', $ini->get('suhosin.executor.func.blacklist'));
$disabled = array_map('trim', $disabled);
if (in_array($function_name, $disabled)) {
return false;
diff --git a/lib/private/l10n.php b/lib/private/l10n.php
index 86335bce92f..7835285bd49 100644
--- a/lib/private/l10n.php
+++ b/lib/private/l10n.php
@@ -116,13 +116,17 @@ class OC_L10N implements \OCP\IL10N {
$preferred_language = str_replace('-', '_', $preferred_language);
foreach ($available as $available_language) {
if ($preferred_language === strtolower($available_language)) {
- self::$language = $available_language;
+ if (!self::$language) {
+ self::$language = $available_language;
+ }
return $available_language;
}
}
foreach ($available as $available_language) {
if (substr($preferred_language, 0, 2) === $available_language) {
- self::$language = $available_language;
+ if (!self::$language) {
+ self::$language = $available_language;
+ }
return $available_language;
}
}
@@ -407,7 +411,7 @@ class OC_L10N implements \OCP\IL10N {
* If nothing works it returns 'en'
*/
public static function findLanguage($app = null) {
- if(self::$language != '') {
+ if (self::$language != '' && self::languageExists($app, self::$language)) {
return self::$language;
}
diff --git a/lib/private/lock/abstractlockingprovider.php b/lib/private/lock/abstractlockingprovider.php
index c7a29380efe..db5f1c72dd7 100644
--- a/lib/private/lock/abstractlockingprovider.php
+++ b/lib/private/lock/abstractlockingprovider.php
@@ -28,6 +28,8 @@ use OCP\Lock\ILockingProvider;
* to release any left over locks at the end of the request
*/
abstract class AbstractLockingProvider implements ILockingProvider {
+ const TTL = 3600; // how long until we clear stray locks in seconds
+
protected $acquiredLocks = [
'shared' => [],
'exclusive' => []
diff --git a/lib/private/lock/dblockingprovider.php b/lib/private/lock/dblockingprovider.php
index 90657e6725f..1b5142a90d2 100644
--- a/lib/private/lock/dblockingprovider.php
+++ b/lib/private/lock/dblockingprovider.php
@@ -51,8 +51,6 @@ class DBLockingProvider extends AbstractLockingProvider {
private $sharedLocks = [];
- const TTL = 3600; // how long until we clear stray locks in seconds
-
/**
* Check if we have an open shared lock for a path
*
@@ -235,10 +233,10 @@ class DBLockingProvider extends AbstractLockingProvider {
/**
* cleanup empty locks
*/
- public function cleanEmptyLocks() {
+ public function cleanExpiredLocks() {
$expire = $this->timeFactory->getTime();
$this->connection->executeUpdate(
- 'DELETE FROM `*PREFIX*file_locks` WHERE `lock` = 0 AND `ttl` < ?',
+ 'DELETE FROM `*PREFIX*file_locks` WHERE `ttl` < ?',
[$expire]
);
}
@@ -262,7 +260,7 @@ class DBLockingProvider extends AbstractLockingProvider {
public function __destruct() {
try {
- $this->cleanEmptyLocks();
+ $this->cleanExpiredLocks();
} catch (\Exception $e) {
// If the table is missing, the clean up was successful
if ($this->connection->tableExists('file_locks')) {
diff --git a/lib/private/lock/memcachelockingprovider.php b/lib/private/lock/memcachelockingprovider.php
index e4158dcdfdf..af95200d159 100644
--- a/lib/private/lock/memcachelockingprovider.php
+++ b/lib/private/lock/memcachelockingprovider.php
@@ -21,6 +21,7 @@
namespace OC\Lock;
+use OCP\IMemcacheTTL;
use OCP\Lock\LockedException;
use OCP\IMemcache;
@@ -37,6 +38,12 @@ class MemcacheLockingProvider extends AbstractLockingProvider {
$this->memcache = $memcache;
}
+ private function setTTL($path) {
+ if ($this->memcache instanceof IMemcacheTTL) {
+ $this->memcache->setTTL($path, self::TTL);
+ }
+ }
+
/**
* @param string $path
* @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE
@@ -69,6 +76,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider {
throw new LockedException($path);
}
}
+ $this->setTTL($path);
$this->markAcquire($path, $type);
}
@@ -106,6 +114,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider {
throw new LockedException($path);
}
}
+ $this->setTTL($path);
$this->markChange($path, $targetType);
}
}
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/memcache/apc.php b/lib/private/memcache/apc.php
index f768cdc1c6e..e38b4bd3a39 100644
--- a/lib/private/memcache/apc.php
+++ b/lib/private/memcache/apc.php
@@ -115,9 +115,9 @@ class APC extends Cache implements IMemcache {
static public function isAvailable() {
if (!extension_loaded('apc')) {
return false;
- } elseif (!ini_get('apc.enabled')) {
+ } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
return false;
- } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) {
+ } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
return false;
} else {
return true;
diff --git a/lib/private/memcache/apcu.php b/lib/private/memcache/apcu.php
index 9a8da2ae60c..84147233ef0 100644
--- a/lib/private/memcache/apcu.php
+++ b/lib/private/memcache/apcu.php
@@ -28,9 +28,9 @@ class APCu extends APC {
static public function isAvailable() {
if (!extension_loaded('apcu')) {
return false;
- } elseif (!ini_get('apc.enabled')) {
+ } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
return false;
- } elseif (!ini_get('apc.enable_cli') && \OC::$CLI) {
+ } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
return false;
} elseif (version_compare(phpversion('apc'), '4.0.6') === -1) {
return false;
diff --git a/lib/private/memcache/redis.php b/lib/private/memcache/redis.php
index 83be662eabf..68b62e7534a 100644
--- a/lib/private/memcache/redis.php
+++ b/lib/private/memcache/redis.php
@@ -25,9 +25,9 @@
namespace OC\Memcache;
-use OCP\IMemcache;
+use OCP\IMemcacheTTL;
-class Redis extends Cache implements IMemcache {
+class Redis extends Cache implements IMemcacheTTL {
/**
* @var \Redis $cache
*/
@@ -195,6 +195,10 @@ class Redis extends Cache implements IMemcache {
return false;
}
+ public function setTTL($key, $ttl) {
+ self::$cache->expire($this->getNamespace() . $key, $ttl);
+ }
+
static public function isAvailable() {
return extension_loaded('redis')
&& version_compare(phpversion('redis'), '2.2.5', '>=');
diff --git a/lib/private/memcache/xcache.php b/lib/private/memcache/xcache.php
index a6265ed5622..0d2e43a1c18 100644
--- a/lib/private/memcache/xcache.php
+++ b/lib/private/memcache/xcache.php
@@ -118,13 +118,13 @@ class XCache extends Cache implements IMemcache {
if (\OC::$CLI && !getenv('XCACHE_TEST')) {
return false;
}
- if (!function_exists('xcache_unset_by_prefix') && ini_get('xcache.admin.enable_auth')) {
+ if (!function_exists('xcache_unset_by_prefix') && \OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
// We do not want to use XCache if we can not clear it without
// using the administration function xcache_clear_cache()
// AND administration functions are password-protected.
return false;
}
- $var_size = (int)ini_get('xcache.var_size');
+ $var_size = \OC::$server->getIniWrapper()->getNumeric('xcache.var_size');
if (!$var_size) {
return false;
}
diff --git a/lib/private/preview.php b/lib/private/preview.php
index b2accdfd00f..38c043030fc 100644
--- a/lib/private/preview.php
+++ b/lib/private/preview.php
@@ -1250,7 +1250,7 @@ class Preview {
* @param array $args
* @param string $prefix
*/
- public static function prepare_delete($args, $prefix = '') {
+ public static function prepare_delete(array $args, $prefix = '') {
$path = $args['path'];
if (substr($path, 0, 1) === '/') {
$path = substr($path, 1);
@@ -1259,7 +1259,11 @@ class Preview {
$view = new \OC\Files\View('/' . \OC_User::getUser() . '/' . $prefix);
$absPath = Files\Filesystem::normalizePath($view->getAbsolutePath($path));
- self::addPathToDeleteFileMapper($absPath, $view->getFileInfo($path));
+ $fileInfo = $view->getFileInfo($path);
+ if($fileInfo === false) {
+ return;
+ }
+ self::addPathToDeleteFileMapper($absPath, $fileInfo);
if ($view->is_dir($path)) {
$children = self::getAllChildren($view, $path);
self::$deleteChildrenMapper[$absPath] = $children;
diff --git a/lib/private/repair.php b/lib/private/repair.php
index f6ac7ebe65b..d870b472c4f 100644
--- a/lib/private/repair.php
+++ b/lib/private/repair.php
@@ -40,7 +40,6 @@ use OC\Repair\SqliteAutoincrement;
use OC\Repair\DropOldTables;
use OC\Repair\FillETags;
use OC\Repair\InnoDB;
-use OC\Repair\RepairConfig;
use OC\Repair\RepairLegacyStorages;
use OC\Repair\RepairMimeTypes;
use OC\Repair\SearchLuceneTables;
@@ -107,7 +106,6 @@ class Repair extends BasicEmitter {
return [
new RepairMimeTypes(\OC::$server->getConfig()),
new RepairLegacyStorages(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
- new RepairConfig(),
new AssetCache(),
new FillETags(\OC::$server->getDatabaseConnection()),
new CleanTags(\OC::$server->getDatabaseConnection()),
@@ -138,13 +136,12 @@ class Repair extends BasicEmitter {
* @return array of RepairStep instances
*/
public static function getBeforeUpgradeRepairSteps() {
- $steps = array(
+ $steps = [
new InnoDB(),
new Collation(\OC::$server->getConfig(), \OC_DB::getConnection()),
new SqliteAutoincrement(\OC_DB::getConnection()),
new SearchLuceneTables(),
- new RepairConfig()
- );
+ ];
//There is no need to delete all previews on every single update
//only 7.0.0 through 7.0.2 generated broken previews
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/security/trusteddomainhelper.php b/lib/private/security/trusteddomainhelper.php
index 6dbaadfdb60..c1a397dd52d 100644
--- a/lib/private/security/trusteddomainhelper.php
+++ b/lib/private/security/trusteddomainhelper.php
@@ -74,16 +74,11 @@ class TrustedDomainHelper {
return false;
}
- // TODO: Workaround for older instances still with port applied. Remove for ownCloud 9.
- if(in_array($domainWithPort, $trustedList)) {
- return true;
- }
-
// Always allow access from localhost
if (preg_match(Request::REGEX_LOCALHOST, $domain) === 1) {
return true;
}
- return in_array($domain, $trustedList);
+ return in_array($domain, $trustedList, true);
}
}
diff --git a/lib/private/server.php b/lib/private/server.php
index 6692e6f6bbf..8439500706d 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -528,6 +528,13 @@ class Server extends SimpleContainer implements IServerContainer {
});
return $manager;
});
+ $this->registerService('CommentsManager', function(Server $c) {
+ $config = $c->getConfig();
+ $factoryClass = $config->getSystemValue('comments.managerFactory', '\OC\Comments\ManagerFactory');
+ /** @var \OCP\Comments\ICommentsManagerFactory $factory */
+ $factory = new $factoryClass();
+ return $factory->getManager();
+ });
$this->registerService('EventDispatcher', function() {
return new EventDispatcher();
});
@@ -1122,6 +1129,13 @@ class Server extends SimpleContainer implements IServerContainer {
}
/**
+ * @return \OCP\Comments\ICommentsManager
+ */
+ public function getCommentsManager() {
+ return $this->query('CommentsManager');
+ }
+
+ /**
* @return \OC\IntegrityCheck\Checker
*/
public function getIntegrityCodeChecker() {
diff --git a/lib/private/session/cryptowrapper.php b/lib/private/session/cryptowrapper.php
index c79778587e0..177f11ffb70 100644
--- a/lib/private/session/cryptowrapper.php
+++ b/lib/private/session/cryptowrapper.php
@@ -23,7 +23,6 @@
namespace OC\Session;
-use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
diff --git a/lib/private/setup.php b/lib/private/setup.php
index 814d78679e2..4d11cb44a83 100644
--- a/lib/private/setup.php
+++ b/lib/private/setup.php
@@ -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/setup/mysql.php b/lib/private/setup/mysql.php
index f2d2b15cd90..e8b88eb3489 100644
--- a/lib/private/setup/mysql.php
+++ b/lib/private/setup/mysql.php
@@ -89,15 +89,28 @@ class MySQL extends AbstractDatabase {
* @throws \OC\DatabaseSetupException
*/
private function connect() {
- $type = 'mysql';
+
$connectionParams = array(
- 'host' => $this->dbHost,
- 'user' => $this->dbUser,
- 'password' => $this->dbPassword,
- 'tablePrefix' => $this->tablePrefix,
+ 'host' => $this->dbHost,
+ 'user' => $this->dbUser,
+ 'password' => $this->dbPassword,
+ 'tablePrefix' => $this->tablePrefix,
);
+
+ // adding port support
+ if (strpos($this->dbHost, ':')) {
+ // Host variable may carry a port or socket.
+ list($host, $portOrSocket) = explode(':', $this->dbHost, 2);
+ if (ctype_digit($portOrSocket)) {
+ $connectionParams['port'] = $portOrSocket;
+ } else {
+ $connectionParams['unix_socket'] = $portOrSocket;
+ }
+ $connectionParams['host'] = $host;
+ }
+
$cf = new ConnectionFactory();
- return $cf->getConnection($type, $connectionParams);
+ return $cf->getConnection('mysql', $connectionParams);
}
/**
diff --git a/lib/private/share/mailnotifications.php b/lib/private/share/mailnotifications.php
index f45d80b37ca..f071c7f3a3c 100644
--- a/lib/private/share/mailnotifications.php
+++ b/lib/private/share/mailnotifications.php
@@ -170,16 +170,18 @@ 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]);
list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration);
+ $recipient = str_replace([', ', '; ', ',', ';', ' '], ',', $recipient);
+ $recipients = explode(',', $recipient);
try {
$message = $this->mailer->createMessage();
$message->setSubject($subject);
- $message->setTo([$recipient]);
+ $message->setTo($recipients);
$message->setHtmlBody($htmlBody);
$message->setPlainBody($textBody);
$message->setFrom([
@@ -230,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 70f9a6e8920..3edffba8a3f 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -635,7 +635,7 @@ class Share extends Constants {
throw new \Exception($message_t);
}
// verify that the user has share permission
- if (!\OC\Files\Filesystem::isSharable($path)) {
+ if (!\OC\Files\Filesystem::isSharable($path) || \OCP\Util::isSharingDisabledForUser()) {
$message = 'You are not allowed to share %s';
$message_t = $l->t('You are not allowed to share %s', [$path]);
\OCP\Util::writeLog('OCP\Share', sprintf($message, $path), \OCP\Util::DEBUG);
@@ -745,10 +745,8 @@ class Share extends Constants {
// The check for each user in the group is done inside the put() function
if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith,
null, self::FORMAT_NONE, null, 1, true, true)) {
- // Only allow the same share to occur again if it is the same
- // owner and is not a group share, this use case is for increasing
- // permissions for a specific user
- if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
+
+ if ($checkExists['share_with'] === $shareWith && $checkExists['share_type'] === \OCP\Share::SHARE_TYPE_GROUP) {
$message = 'Sharing %s failed, because this item is already shared with %s';
$message_t = $l->t('Sharing %s failed, because this item is already shared with %s', array($itemSourceName, $shareWith));
\OCP\Util::writeLog('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OCP\Util::DEBUG);
@@ -764,6 +762,11 @@ class Share extends Constants {
$updateExistingShare = false;
if (\OC::$server->getAppConfig()->getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
+ // IF the password is changed via the old ajax endpoint verify it before deleting the old share
+ if ($passwordChanged === true) {
+ self::verifyPassword($shareWith);
+ }
+
// when updating a link share
// FIXME Don't delete link if we update it
if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null,
diff --git a/lib/private/systemtag/systemtagmanager.php b/lib/private/systemtag/systemtagmanager.php
index 8caf10d69da..7f239dc84cf 100644
--- a/lib/private/systemtag/systemtagmanager.php
+++ b/lib/private/systemtag/systemtagmanager.php
@@ -63,7 +63,7 @@ class SystemTagManager implements ISystemTagManager {
/**
* {@inheritdoc}
*/
- public function getTagsById($tagIds) {
+ public function getTagsByIds($tagIds) {
if (!is_array($tagIds)) {
$tagIds = [$tagIds];
}
@@ -242,7 +242,7 @@ class SystemTagManager implements ISystemTagManager {
$tagNotFoundException = null;
try {
- $this->getTagsById($tagIds);
+ $this->getTagsByIds($tagIds);
} catch (TagNotFoundException $e) {
$tagNotFoundException = $e;
}
diff --git a/lib/private/systemtag/systemtagobjectmapper.php b/lib/private/systemtag/systemtagobjectmapper.php
index 75f2631a010..988fa66d77e 100644
--- a/lib/private/systemtag/systemtagobjectmapper.php
+++ b/lib/private/systemtag/systemtagobjectmapper.php
@@ -171,6 +171,10 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper {
public function haveTag($objIds, $objectType, $tagId, $all = true) {
$this->assertTagsExist([$tagId]);
+ if (!is_array($objIds)) {
+ $objIds = [$objIds];
+ }
+
$query = $this->connection->getQueryBuilder();
if (!$all) {
@@ -209,7 +213,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper {
* @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist
*/
private function assertTagsExist($tagIds) {
- $tags = $this->tagManager->getTagsById($tagIds);
+ $tags = $this->tagManager->getTagsByIds($tagIds);
if (count($tags) !== count($tagIds)) {
// at least one tag missing, bail out
$foundTagIds = array_map(
diff --git a/lib/private/template.php b/lib/private/template.php
index 1476a964ef3..d794dacac23 100644
--- a/lib/private/template.php
+++ b/lib/private/template.php
@@ -226,12 +226,12 @@ class OC_Template extends \OC\Template\Base {
// Add custom headers
$headers = '';
foreach(OC_Util::$headers as $header) {
- $headers .= '<'.OC_Util::sanitizeHTML($header['tag']);
+ $headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
foreach($header['attributes'] as $name=>$value) {
- $headers .= ' '.OC_Util::sanitizeHTML($name).'="'.OC_Util::sanitizeHTML($value).'"';
+ $headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
}
if ($header['text'] !== null) {
- $headers .= '>'.OC_Util::sanitizeHTML($header['text']).'</'.OC_Util::sanitizeHTML($header['tag']).'>';
+ $headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>';
} else {
$headers .= '/>';
}
diff --git a/lib/private/template/functions.php b/lib/private/template/functions.php
index 79d18632d2f..d156d26f9ce 100644
--- a/lib/private/template/functions.php
+++ b/lib/private/template/functions.php
@@ -33,7 +33,7 @@
* @param string $string the string which will be escaped and printed
*/
function p($string) {
- print(OC_Util::sanitizeHTML($string));
+ print(\OCP\Util::sanitizeHTML($string));
}
/**
@@ -262,7 +262,7 @@ function html_select_options($options, $selected, $params=array()) {
$label = $label[$label_name];
}
$select = in_array($value, $selected) ? ' selected="selected"' : '';
- $html .= '<option value="' . OC_Util::sanitizeHTML($value) . '"' . $select . '>' . OC_Util::sanitizeHTML($label) . '</option>'."\n";
+ $html .= '<option value="' . \OCP\Util::sanitizeHTML($value) . '"' . $select . '>' . \OCP\Util::sanitizeHTML($label) . '</option>'."\n";
}
return $html;
}
diff --git a/lib/private/tempmanager.php b/lib/private/tempmanager.php
index 365d639389f..ac44b76d683 100644
--- a/lib/private/tempmanager.php
+++ b/lib/private/tempmanager.php
@@ -213,7 +213,7 @@ class TempManager implements ITempManager {
if ($temp = $this->config->getSystemValue('tempdirectory', null)) {
$directories[] = $temp;
}
- if ($temp = ini_get('upload_tmp_dir')) {
+ if ($temp = \OC::$server->getIniWrapper()->get('upload_tmp_dir')) {
$directories[] = $temp;
}
if ($temp = getenv('TMP')) {
diff --git a/lib/private/user/user.php b/lib/private/user/user.php
index d827097ee39..6c89dd06f77 100644
--- a/lib/private/user/user.php
+++ b/lib/private/user/user.php
@@ -189,6 +189,8 @@ class User implements IUser {
// Delete the users entry in the storage table
\OC\Files\Cache\Storage::remove('home::' . $this->uid);
+
+ \OC::$server->getCommentsManager()->deleteReferencesOfActor('user', $this->uid);
}
if ($this->emitter) {
diff --git a/lib/private/util.php b/lib/private/util.php
index ac42b96de2d..9016dc59751 100644
--- a/lib/private/util.php
+++ b/lib/private/util.php
@@ -642,13 +642,15 @@ class OC_Util {
}
// Check if config folder is writable.
- if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
- $errors[] = array(
- 'error' => $l->t('Cannot write into "config" directory'),
- 'hint' => $l->t('This can usually be fixed by '
- . '%sgiving the webserver write access to the config directory%s.',
- array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
- );
+ if(!OC_Helper::isReadOnlyConfigEnabled()) {
+ if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
+ $errors[] = array(
+ 'error' => $l->t('Cannot write into "config" directory'),
+ 'hint' => $l->t('This can usually be fixed by '
+ . '%sgiving the webserver write access to the config directory%s.',
+ array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank">', '</a>'))
+ );
+ }
}
// Check if there is a writable install folder.
@@ -947,6 +949,14 @@ class OC_Util {
$parameters['redirect_url'] = $_REQUEST['redirect_url'];
}
+ $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();
+ }
+ }
+
$parameters['alt_login'] = OC_App::getAlternativeLogIns();
$parameters['rememberLoginAllowed'] = self::rememberLoginAllowed();
\OC_Hook::emit('OC_Util', 'pre_displayLoginPage', array('parameters' => $parameters));
@@ -1169,14 +1179,16 @@ class OC_Util {
* This function is used to sanitize HTML and should be applied on any
* string or array of strings before displaying it on a web page.
*
- * @param string|array &$value
+ * @param string|array $value
* @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
*/
- public static function sanitizeHTML(&$value) {
+ public static function sanitizeHTML($value) {
if (is_array($value)) {
- array_walk_recursive($value, 'OC_Util::sanitizeHTML');
+ $value = array_map(function($value) {
+ return self::sanitizeHTML($value);
+ }, $value);
} else {
- //Specify encoding for PHP<5.4
+ // Specify encoding for PHP<5.4
$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
}
return $value;
@@ -1237,7 +1249,11 @@ class OC_Util {
// accessing the file via http
$url = OC_Helper::makeURLAbsolute(OC::$WEBROOT . '/data' . $fileName);
- $content = self::getUrlContent($url);
+ try {
+ $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
+ } catch (\Exception $e) {
+ $content = false;
+ }
// cleanup
@unlink($testFile);
@@ -1313,23 +1329,6 @@ class OC_Util {
}
/**
- * Get URL content
- * @param string $url Url to get content
- * @throws Exception If the URL does not start with http:// or https://
- * @return string of the response or false on error
- * This function get the content of a page via curl, if curl is enabled.
- * If not, file_get_contents is used.
- * @deprecated Use \OC::$server->getHTTPClientService()->newClient()->get($url);
- */
- public static function getUrlContent($url) {
- try {
- return \OC::$server->getHTTPHelper()->getUrlContent($url);
- } catch (\Exception $e) {
- throw $e;
- }
- }
-
- /**
* Checks whether the server is running on Windows
*
* @return bool true if running on Windows, false otherwise
@@ -1418,7 +1417,7 @@ class OC_Util {
}
// XCache
if (function_exists('xcache_clear_cache')) {
- if (ini_get('xcache.admin.enable_auth')) {
+ if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
\OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN);
} else {
@xcache_clear_cache(XC_TYPE_PHP, 0);