summaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/AppFramework/Http/Request.php48
-rw-r--r--lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php4
-rw-r--r--lib/private/Authentication/Exceptions/ExpiredTokenException.php4
-rw-r--r--lib/private/Authentication/Token/DefaultTokenProvider.php1
-rw-r--r--lib/private/Authentication/Token/IProvider.php1
-rw-r--r--lib/private/Authentication/Token/Manager.php1
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenProvider.php1
-rw-r--r--lib/private/Collaboration/Collaborators/MailPlugin.php21
-rw-r--r--lib/private/Collaboration/Collaborators/RemotePlugin.php69
-rw-r--r--lib/private/Files/FileInfo.php4
-rw-r--r--lib/private/Files/Node/File.php4
-rw-r--r--lib/private/Files/Node/LazyRoot.php4
-rw-r--r--lib/private/Files/Node/Node.php4
-rw-r--r--lib/private/Files/Storage/Wrapper/Quota.php2
-rw-r--r--lib/private/FullTextSearch/FullTextSearchManager.php227
-rw-r--r--lib/private/Server.php6
-rw-r--r--lib/private/Share20/DefaultShareProvider.php2
-rw-r--r--lib/private/Share20/Share.php13
-rw-r--r--lib/private/Template/IconsCacher.php119
-rw-r--r--lib/private/Template/JSConfigHelper.php5
-rw-r--r--lib/private/User/Session.php12
21 files changed, 512 insertions, 40 deletions
diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php
index 0485d178b49..2c745973ed2 100644
--- a/lib/private/AppFramework/Http/Request.php
+++ b/lib/private/AppFramework/Http/Request.php
@@ -320,14 +320,18 @@ class Request implements \ArrayAccess, \Countable, IRequest {
// There's a few headers that seem to end up in the top-level
// server array.
- switch($name) {
+ switch ($name) {
case 'CONTENT_TYPE' :
case 'CONTENT_LENGTH' :
if (isset($this->server[$name])) {
return $this->server[$name];
}
break;
-
+ case 'REMOTE_ADDR' :
+ if (isset($this->server[$name])) {
+ return $this->server[$name];
+ }
+ break;
}
return '';
@@ -595,6 +599,44 @@ class Request implements \ArrayAccess, \Countable, IRequest {
}
/**
+ * Checks if given $remoteAddress matches given $trustedProxy.
+ * If $trustedProxy is an IPv4 IP range given in CIDR notation, true will be returned if
+ * $remoteAddress is an IPv4 address within that IP range.
+ * Otherwise $remoteAddress will be compared to $trustedProxy literally and the result
+ * will be returned.
+ * @return boolean true if $remoteAddress matches $trustedProxy, false otherwise
+ */
+ protected function matchesTrustedProxy($trustedProxy, $remoteAddress) {
+ $cidrre = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/([0-9]{1,2})$/';
+
+ if (preg_match($cidrre, $trustedProxy, $match)) {
+ $net = $match[1];
+ $shiftbits = min(32, max(0, 32 - intval($match[2])));
+ $netnum = ip2long($net) >> $shiftbits;
+ $ipnum = ip2long($remoteAddress) >> $shiftbits;
+
+ return $ipnum === $netnum;
+ }
+
+ return $trustedProxy === $remoteAddress;
+ }
+
+ /**
+ * Checks if given $remoteAddress matches any entry in the given array $trustedProxies.
+ * For details regarding what "match" means, refer to `matchesTrustedProxy`.
+ * @return boolean true if $remoteAddress matches any entry in $trustedProxies, false otherwise
+ */
+ protected function isTrustedProxy($trustedProxies, $remoteAddress) {
+ foreach ($trustedProxies as $tp) {
+ if ($this->matchesTrustedProxy($tp, $remoteAddress)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Returns the remote address, if the connection came from a trusted proxy
* and `forwarded_for_headers` has been configured then the IP address
* specified in this header will be returned instead.
@@ -605,7 +647,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
$remoteAddress = isset($this->server['REMOTE_ADDR']) ? $this->server['REMOTE_ADDR'] : '';
$trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
- if(\is_array($trustedProxies) && \in_array($remoteAddress, $trustedProxies)) {
+ if(\is_array($trustedProxies) && $this->isTrustedProxy($trustedProxies, $remoteAddress)) {
$forwardedForHeaders = $this->config->getSystemValue('forwarded_for_headers', [
'HTTP_X_FORWARDED_FOR'
// only have one default, so we cannot ship an insecure product out of the box
diff --git a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
index 463e7cd93c9..7c1c4595e9a 100644
--- a/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/PasswordConfirmationMiddleware.php
@@ -39,6 +39,8 @@ class PasswordConfirmationMiddleware extends Middleware {
private $userSession;
/** @var ITimeFactory */
private $timeFactory;
+ /** @var array */
+ private $excludedUserBackEnds = ['user_saml' => true, 'user_globalsiteselector' => true];
/**
* PasswordConfirmationMiddleware constructor.
@@ -73,7 +75,7 @@ class PasswordConfirmationMiddleware extends Middleware {
$lastConfirm = (int) $this->session->get('last-password-confirm');
// we can't check the password against a SAML backend, so skip password confirmation in this case
- if ($backendClassName !== 'user_saml' && $lastConfirm < ($this->timeFactory->getTime() - (30 * 60 + 15))) { // allow 15 seconds delay
+ if (!isset($this->excludedUserBackEnds[$backendClassName]) && $lastConfirm < ($this->timeFactory->getTime() - (30 * 60 + 15))) { // allow 15 seconds delay
throw new NotConfirmedException();
}
}
diff --git a/lib/private/Authentication/Exceptions/ExpiredTokenException.php b/lib/private/Authentication/Exceptions/ExpiredTokenException.php
index a45ca5b6955..d5b2e2cbca7 100644
--- a/lib/private/Authentication/Exceptions/ExpiredTokenException.php
+++ b/lib/private/Authentication/Exceptions/ExpiredTokenException.php
@@ -21,9 +21,9 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-namespace OC\Authentication\Token;
+namespace OC\Authentication\Exceptions;
-use OC\Authentication\Exceptions\InvalidTokenException;
+use OC\Authentication\Token\IToken;
class ExpiredTokenException extends InvalidTokenException {
/** @var IToken */
diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php
index a27a875a27f..98609a3f14b 100644
--- a/lib/private/Authentication/Token/DefaultTokenProvider.php
+++ b/lib/private/Authentication/Token/DefaultTokenProvider.php
@@ -29,6 +29,7 @@ declare(strict_types=1);
namespace OC\Authentication\Token;
use Exception;
+use OC\Authentication\Exceptions\ExpiredTokenException;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
use OCP\AppFramework\Db\DoesNotExistException;
diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php
index 7ee76b7b384..21223cecdf7 100644
--- a/lib/private/Authentication/Token/IProvider.php
+++ b/lib/private/Authentication/Token/IProvider.php
@@ -26,6 +26,7 @@ declare(strict_types=1);
namespace OC\Authentication\Token;
+use OC\Authentication\Exceptions\ExpiredTokenException;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php
index 98a48f41523..3174599221d 100644
--- a/lib/private/Authentication/Token/Manager.php
+++ b/lib/private/Authentication/Token/Manager.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace OC\Authentication\Token;
+use OC\Authentication\Exceptions\ExpiredTokenException;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
index 33c0b1d59eb..9f596ac4568 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace OC\Authentication\Token;
+use OC\Authentication\Exceptions\ExpiredTokenException;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
use OCP\AppFramework\Db\DoesNotExistException;
diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php
index 101d6845ec3..6faa5d5d125 100644
--- a/lib/private/Collaboration/Collaborators/MailPlugin.php
+++ b/lib/private/Collaboration/Collaborators/MailPlugin.php
@@ -84,11 +84,17 @@ class MailPlugin implements ISearchPlugin {
foreach ($addressBookContacts as $contact) {
if (isset($contact['EMAIL'])) {
$emailAddresses = $contact['EMAIL'];
- if (!is_array($emailAddresses)) {
+ if (\is_string($emailAddresses)) {
$emailAddresses = [$emailAddresses];
}
- foreach ($emailAddresses as $emailAddress) {
+ foreach ($emailAddresses as $type => $emailAddress) {
$displayName = $emailAddress;
+ $emailAddressType = null;
+ if (\is_array($emailAddress)) {
+ $emailAddressData = $emailAddress;
+ $emailAddress = $emailAddressData['value'];
+ $emailAddressType = $emailAddressData['type'];
+ }
if (isset($contact['FN'])) {
$displayName = $contact['FN'] . ' (' . $emailAddress . ')';
}
@@ -121,6 +127,8 @@ class MailPlugin implements ISearchPlugin {
if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) {
$singleResult = [[
'label' => $displayName,
+ 'uuid' => $contact['UID'],
+ 'name' => $contact['FN'],
'value' => [
'shareType' => Share::SHARE_TYPE_USER,
'shareWith' => $cloud->getUser(),
@@ -142,6 +150,8 @@ class MailPlugin implements ISearchPlugin {
if (!$this->isCurrentUser($cloud) && !$searchResult->hasResult($userType, $cloud->getUser())) {
$userResults['wide'][] = [
'label' => $displayName,
+ 'uuid' => $contact['UID'],
+ 'name' => $contact['FN'],
'value' => [
'shareType' => Share::SHARE_TYPE_USER,
'shareWith' => $cloud->getUser(),
@@ -160,6 +170,9 @@ class MailPlugin implements ISearchPlugin {
}
$result['exact'][] = [
'label' => $displayName,
+ 'uuid' => $contact['UID'],
+ 'name' => $contact['FN'],
+ 'type' => $emailAddressType ?? '',
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $emailAddress,
@@ -168,6 +181,9 @@ class MailPlugin implements ISearchPlugin {
} else {
$result['wide'][] = [
'label' => $displayName,
+ 'uuid' => $contact['UID'],
+ 'name' => $contact['FN'],
+ 'type' => $emailAddressType ?? '',
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $emailAddress,
@@ -194,6 +210,7 @@ class MailPlugin implements ISearchPlugin {
if (!$searchResult->hasExactIdMatch($emailType) && filter_var($search, FILTER_VALIDATE_EMAIL)) {
$result['exact'][] = [
'label' => $search,
+ 'uuid' => $search,
'value' => [
'shareType' => Share::SHARE_TYPE_EMAIL,
'shareWith' => $search,
diff --git a/lib/private/Collaboration/Collaborators/RemotePlugin.php b/lib/private/Collaboration/Collaborators/RemotePlugin.php
index e0f5298f83b..d877346b155 100644
--- a/lib/private/Collaboration/Collaborators/RemotePlugin.php
+++ b/lib/private/Collaboration/Collaborators/RemotePlugin.php
@@ -30,6 +30,8 @@ use OCP\Collaboration\Collaborators\SearchResultType;
use OCP\Contacts\IManager;
use OCP\Federation\ICloudIdManager;
use OCP\IConfig;
+use OCP\IUserManager;
+use OCP\IUserSession;
use OCP\Share;
class RemotePlugin implements ISearchPlugin {
@@ -41,12 +43,20 @@ class RemotePlugin implements ISearchPlugin {
private $cloudIdManager;
/** @var IConfig */
private $config;
+ /** @var IUserManager */
+ private $userManager;
+ /** @var string */
+ private $userId = '';
- public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config) {
+ public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) {
$this->contactsManager = $contactsManager;
$this->cloudIdManager = $cloudIdManager;
$this->config = $config;
-
+ $this->userManager = $userManager;
+ $user = $userSession->getUser();
+ if ($user !== null) {
+ $this->userId = $user->getUID();
+ }
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
}
@@ -63,23 +73,47 @@ class RemotePlugin implements ISearchPlugin {
}
if (isset($contact['CLOUD'])) {
$cloudIds = $contact['CLOUD'];
- if (!is_array($cloudIds)) {
+ if (is_string($cloudIds)) {
$cloudIds = [$cloudIds];
}
$lowerSearch = strtolower($search);
foreach ($cloudIds as $cloudId) {
+ $cloudIdType = '';
+ if (\is_array($cloudId)) {
+ $cloudIdData = $cloudId;
+ $cloudId = $cloudIdData['value'];
+ $cloudIdType = $cloudIdData['type'];
+ }
try {
- list(, $serverUrl) = $this->splitUserRemote($cloudId);
+ list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId);
} catch (\InvalidArgumentException $e) {
continue;
}
+ $localUser = $this->userManager->get($remoteUser);
+ /**
+ * Add local share if remote cloud id matches a local user ones
+ */
+ if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId() ) {
+ $result['wide'][] = [
+ 'label' => $contact['FN'],
+ 'uuid' => $contact['UID'],
+ 'value' => [
+ 'shareType' => Share::SHARE_TYPE_USER,
+ 'shareWith' => $remoteUser
+ ]
+ ];
+ }
+
if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
if (strtolower($cloudId) === $lowerSearch) {
$searchResult->markExactIdMatch($resultType);
}
$result['exact'][] = [
'label' => $contact['FN'] . " ($cloudId)",
+ 'uuid' => $contact['UID'],
+ 'name' => $contact['FN'],
+ 'type' => $cloudIdType,
'value' => [
'shareType' => Share::SHARE_TYPE_REMOTE,
'shareWith' => $cloudId,
@@ -89,6 +123,9 @@ class RemotePlugin implements ISearchPlugin {
} else {
$result['wide'][] = [
'label' => $contact['FN'] . " ($cloudId)",
+ 'uuid' => $contact['UID'],
+ 'name' => $contact['FN'],
+ 'type' => $cloudIdType,
'value' => [
'shareType' => Share::SHARE_TYPE_REMOTE,
'shareWith' => $cloudId,
@@ -106,14 +143,24 @@ class RemotePlugin implements ISearchPlugin {
$result['wide'] = array_slice($result['wide'], $offset, $limit);
}
+ /**
+ * Add generic share with remote item for valid cloud ids that are not users of the local instance
+ */
if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
- $result['exact'][] = [
- 'label' => $search,
- 'value' => [
- 'shareType' => Share::SHARE_TYPE_REMOTE,
- 'shareWith' => $search,
- ],
- ];
+ try {
+ list($remoteUser, $serverUrl) = $this->splitUserRemote($search);
+ $localUser = $this->userManager->get($remoteUser);
+ if ($localUser === null || $search !== $localUser->getCloudId()) {
+ $result['exact'][] = [
+ 'label' => $search,
+ 'value' => [
+ 'shareType' => Share::SHARE_TYPE_REMOTE,
+ 'shareWith' => $search,
+ ],
+ ];
+ }
+ } catch (\InvalidArgumentException $e) {
+ }
}
$searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
diff --git a/lib/private/Files/FileInfo.php b/lib/private/Files/FileInfo.php
index 53f73f0f95d..575af56ceb5 100644
--- a/lib/private/Files/FileInfo.php
+++ b/lib/private/Files/FileInfo.php
@@ -390,4 +390,8 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
public function getChecksum() {
return $this->data['checksum'];
}
+
+ public function getExtension(): string {
+ return pathinfo($this->getName(), PATHINFO_EXTENSION);
+ }
}
diff --git a/lib/private/Files/Node/File.php b/lib/private/Files/Node/File.php
index 7c411620ca0..a3eabbcc446 100644
--- a/lib/private/Files/Node/File.php
+++ b/lib/private/Files/Node/File.php
@@ -142,4 +142,8 @@ class File extends Node implements \OCP\Files\File {
public function getChecksum() {
return $this->getFileInfo()->getChecksum();
}
+
+ public function getExtension(): string {
+ return $this->getFileInfo()->getExtension();
+ }
}
diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php
index faa57ecb0b4..389a1a9f0ff 100644
--- a/lib/private/Files/Node/LazyRoot.php
+++ b/lib/private/Files/Node/LazyRoot.php
@@ -344,6 +344,10 @@ class LazyRoot implements IRootFolder {
return $this->__call(__FUNCTION__, func_get_args());
}
+ public function getExtension(): string {
+ return $this->__call(__FUNCTION__, func_get_args());
+ }
+
/**
* @inheritDoc
*/
diff --git a/lib/private/Files/Node/Node.php b/lib/private/Files/Node/Node.php
index d2232624b9b..590f1080617 100644
--- a/lib/private/Files/Node/Node.php
+++ b/lib/private/Files/Node/Node.php
@@ -354,6 +354,10 @@ class Node implements \OCP\Files\Node {
public function getChecksum() {
}
+ public function getExtension(): string {
+ return $this->getFileInfo()->getExtension();
+ }
+
/**
* @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
* @throws \OCP\Lock\LockedException
diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php
index 860fce57277..4cbe9189593 100644
--- a/lib/private/Files/Storage/Wrapper/Quota.php
+++ b/lib/private/Files/Storage/Wrapper/Quota.php
@@ -83,7 +83,7 @@ class Quota extends Wrapper {
* @return int
*/
public function free_space($path) {
- if ($this->quota < 0 || strpos($path, 'cache') === 0) {
+ if ($this->quota < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
return $this->storage->free_space($path);
} else {
$used = $this->getSize($this->sizeRoot);
diff --git a/lib/private/FullTextSearch/FullTextSearchManager.php b/lib/private/FullTextSearch/FullTextSearchManager.php
new file mode 100644
index 00000000000..6529ef2506a
--- /dev/null
+++ b/lib/private/FullTextSearch/FullTextSearchManager.php
@@ -0,0 +1,227 @@
+<?php
+declare(strict_types=1);
+
+
+/**
+ * FullTextSearch - Full text search framework for Nextcloud
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OC\FullTextSearch;
+
+
+use OCP\FullTextSearch\Exceptions\FullTextSearchAppNotAvailableException;
+use OCP\FullTextSearch\IFullTextSearchManager;
+use OCP\FullTextSearch\Model\IIndex;
+use OCP\FullTextSearch\Model\ISearchResult;
+use OCP\FullTextSearch\Service\IIndexService;
+use OCP\FullTextSearch\Service\IProviderService;
+use OCP\FullTextSearch\Service\ISearchService;
+
+
+/**
+ * Class FullTextSearchManager
+ *
+ * @package OC\FullTextSearch
+ */
+class FullTextSearchManager implements IFullTextSearchManager {
+
+
+ /** @var IProviderService */
+ private $providerService;
+
+ /** @var IIndexService */
+ private $indexService;
+
+ /** @var ISearchService */
+ private $searchService;
+
+
+ /**
+ * @since 15.0.0
+ *
+ * @param IProviderService $providerService
+ */
+ public function registerProviderService(IProviderService $providerService) {
+ $this->providerService = $providerService;
+ }
+
+ /**
+ * @since 15.0.0
+ *
+ * @param IIndexService $indexService
+ */
+ public function registerIndexService(IIndexService $indexService) {
+ $this->indexService = $indexService;
+ }
+
+ /**
+ * @since 15.0.0
+ *
+ * @param ISearchService $searchService
+ */
+ public function registerSearchService(ISearchService $searchService) {
+ $this->searchService = $searchService;
+ }
+
+
+ /**
+ * @return IProviderService
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ private function getProviderService(): IProviderService {
+ if ($this->providerService === null) {
+ throw new FullTextSearchAppNotAvailableException('No IProviderService registered');
+ }
+
+ return $this->providerService;
+ }
+
+
+ /**
+ * @return IIndexService
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ private function getIndexService(): IIndexService {
+ if ($this->indexService === null) {
+ throw new FullTextSearchAppNotAvailableException('No IIndexService registered');
+ }
+
+ return $this->indexService;
+ }
+
+
+ /**
+ * @return ISearchService
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ private function getSearchService(): ISearchService {
+ if ($this->searchService === null) {
+ throw new FullTextSearchAppNotAvailableException('No ISearchService registered');
+ }
+
+ return $this->searchService;
+ }
+
+
+ /**
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ public function addJavascriptAPI() {
+ $this->getProviderService()->addJavascriptAPI();
+ }
+
+
+ /**
+ * @param string $providerId
+ *
+ * @return bool
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ public function isProviderIndexed(string $providerId): bool {
+ return $this->getProviderService()->isProviderIndexed($providerId);
+ }
+
+
+ /**
+ * @param string $providerId
+ * @param string $documentId
+ * @return IIndex
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ public function getIndex(string $providerId, string $documentId): IIndex {
+ return $this->getIndexService()->getIndex($providerId, $documentId);
+ }
+
+ /**
+ * @param string $providerId
+ * @param string $documentId
+ * @param string $userId
+ * @param int $status
+ *
+ * @see IIndex for available value for $status.
+ *
+ * @return IIndex
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ public function createIndex(string $providerId, string $documentId, string $userId, int $status = 0): IIndex {
+ return $this->getIndexService()->getIndex($providerId, $documentId);
+ }
+
+
+ /**
+ * @param string $providerId
+ * @param string $documentId
+ * @param int $status
+ * @param bool $reset
+ *
+ * @see IIndex for available value for $status.
+ *
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ public function updateIndexStatus(string $providerId, string $documentId, int $status, bool $reset = false) {
+ $this->getIndexService()->updateIndexStatus($providerId, $documentId, $status, $reset);
+ }
+
+ /**
+ * @param string $providerId
+ * @param array $documentIds
+ * @param int $status
+ * @param bool $reset
+ *
+ * @see IIndex for available value for $status.
+ *
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ public function updateIndexesStatus(string $providerId, array $documentIds, int $status, bool $reset = false) {
+ $this->getIndexService()->updateIndexStatus($providerId, $documentIds, $status, $reset);
+ }
+
+
+ /**
+ * @param IIndex[] $indexes
+ *
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ public function updateIndexes(array $indexes) {
+ $this->getIndexService()->updateIndexes($indexes);
+ }
+
+
+ /**
+ * @param array $request
+ * @param string $userId
+ *
+ * @return ISearchResult[]
+ * @throws FullTextSearchAppNotAvailableException
+ */
+ public function search(array $request, string $userId = ''): array {
+ $searchRequest = $this->getSearchService()->generateSearchRequest($request);
+
+ return $this->getSearchService()->search($userId, $searchRequest);
+ }
+
+
+}
+
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 32d7705919c..ceecd059df2 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -82,6 +82,7 @@ use OC\Files\Node\LazyRoot;
use OC\Files\Node\Root;
use OC\Files\Storage\StorageFactory;
use OC\Files\View;
+use OC\FullTextSearch\FullTextSearchManager;
use OC\Http\Client\ClientService;
use OC\IntegrityCheck\Checker;
use OC\IntegrityCheck\Helpers\AppLocator;
@@ -138,6 +139,7 @@ use OCP\Federation\ICloudIdManager;
use OCP\Authentication\LoginCredentials\IStore;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorageFactory;
+use OCP\FullTextSearch\IFullTextSearchManager;
use OCP\GlobalScale\IConfig;
use OCP\ICacheFactory;
use OCP\IDBConnection;
@@ -758,7 +760,7 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService('TrustedDomainHelper', function ($c) {
return new TrustedDomainHelper($this->getConfig());
});
- $this->registerService('Throttler', function (Server $c) {
+ $this->registerService(Throttler::class, function (Server $c) {
return new Throttler(
$c->getDatabaseConnection(),
new TimeFactory(),
@@ -766,6 +768,7 @@ class Server extends ServerContainer implements IServerContainer {
$c->getConfig()
);
});
+ $this->registerAlias('Throttler', Throttler::class);
$this->registerService('IntegrityCodeChecker', function (Server $c) {
// IConfig and IAppManager requires a working database. This code
// might however be called when ownCloud is not yet setup.
@@ -1183,6 +1186,7 @@ class Server extends ServerContainer implements IServerContainer {
});
$this->registerAlias(IDashboardManager::class, Dashboard\DashboardManager::class);
+ $this->registerAlias(IFullTextSearchManager::class, FullTextSearchManager::class);
$this->connectDispatcher();
}
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index 9c5d78a5958..3dcca0facbc 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -296,6 +296,7 @@ class DefaultShareProvider implements IShareProvider {
->set('token', $qb->createNamedParameter($share->getToken()))
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
->set('note', $qb->createNamedParameter($share->getNote()))
+ ->set('hide_download', $qb->createNamedParameter($share->getHideDownload() ? 1 : 0), IQueryBuilder::PARAM_INT)
->execute();
}
@@ -953,6 +954,7 @@ class DefaultShareProvider implements IShareProvider {
}
$share->setProviderId($this->identifier());
+ $share->setHideDownload((int)$data['hide_download'] === 1);
return $share;
}
diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php
index 71c0453d9e5..e218360f87b 100644
--- a/lib/private/Share20/Share.php
+++ b/lib/private/Share20/Share.php
@@ -30,6 +30,7 @@ use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\IUserManager;
use OCP\Share\Exceptions\IllegalIDChangeException;
+use OCP\Share\IShare;
class Share implements \OCP\Share\IShare {
@@ -85,6 +86,9 @@ class Share implements \OCP\Share\IShare {
/** @var ICacheEntry|null */
private $nodeCacheEntry;
+ /** @var bool */
+ private $hideDownload = false;
+
public function __construct(IRootFolder $rootFolder, IUserManager $userManager) {
$this->rootFolder = $rootFolder;
$this->userManager = $userManager;
@@ -514,4 +518,13 @@ class Share implements \OCP\Share\IShare {
public function getNodeCacheEntry() {
return $this->nodeCacheEntry;
}
+
+ public function setHideDownload(bool $hide): IShare {
+ $this->hideDownload = $hide;
+ return $this;
+ }
+
+ public function getHideDownload(): bool {
+ return $this->hideDownload;
+ }
}
diff --git a/lib/private/Template/IconsCacher.php b/lib/private/Template/IconsCacher.php
index f3660442dc5..c91bf13ad53 100644
--- a/lib/private/Template/IconsCacher.php
+++ b/lib/private/Template/IconsCacher.php
@@ -47,15 +47,18 @@ class IconsCacher {
protected $urlGenerator;
/** @var string */
- private $iconVarRE = '/--(icon-[a-zA-Z0-9-]+):\s?url\(["\']([a-zA-Z0-9-_\~\/\.\?\=]+)[^;]+;/m';
+ private $iconVarRE = '/--(icon-[a-zA-Z0-9-]+):\s?url\(["\']?([a-zA-Z0-9-_\~\/\.\?\&\=\:\;\+\,]+)[^;]+;/m';
/** @var string */
private $fileName = 'icons-vars.css';
+ private $iconList = 'icons-list.template';
+
/**
* @param ILogger $logger
* @param Factory $appDataFactory
* @param IURLGenerator $urlGenerator
+ * @throws \OCP\Files\NotPermittedException
*/
public function __construct(ILogger $logger,
Factory $appDataFactory,
@@ -71,7 +74,7 @@ class IconsCacher {
}
}
- private function getIconsFromCss(string $css): array{
+ private function getIconsFromCss(string $css): array {
preg_match_all($this->iconVarRE, $css, $matches, PREG_SET_ORDER);
$icons = [];
foreach ($matches as $icon) {
@@ -80,42 +83,112 @@ class IconsCacher {
return $icons;
}
+
/**
- * Parse and cache css
- *
* @param string $css
+ * @return string
+ * @throws NotFoundException
+ * @throws \OCP\Files\NotPermittedException
*/
- public function setIconsCss(string $css) {
+ public function setIconsCss(string $css): string {
- $cachedFile = $this->getCachedCSS();
+ $cachedFile = $this->getCachedList();
if (!$cachedFile) {
$currentData = '';
+ $cachedFile = $this->folder->newFile($this->iconList);
} else {
$currentData = $cachedFile->getContent();
}
- // remove :root
- $currentData = str_replace([':root {', '}'], '', $currentData);
+ $cachedVarsCssFile = $this->getCachedCSS();
+ if (!$cachedVarsCssFile) {
+ $cachedVarsCssFile = $this->folder->newFile($this->fileName);
+ }
$icons = $this->getIconsFromCss($currentData . $css);
$data = '';
+ $list = '';
foreach ($icons as $icon => $url) {
- $data .= "--$icon: url('$url');";
+ $list .= "--$icon: url('$url');";
+ list($location,$color) = $this->parseUrl($url);
+ $svg = false;
+ if ($location !== '') {
+ $svg = file_get_contents($location);
+ }
+ if ($svg === false) {
+ $this->logger->debug('Failed to get icon file ' . $location);
+ $data .= "--$icon: url('$url');";
+ continue;
+ }
+ $encode = base64_encode($this->colorizeSvg($svg, $color));
+ $data .= '--' . $icon . ': url(data:image/svg+xml;base64,' . $encode . ');';
+ }
+
+ if (\strlen($data) > 0 && \strlen($list) > 0) {
+ $data = ":root {\n$data\n}";
+ $cachedVarsCssFile->putContent($data);
+ $list = ":root {\n$list\n}";
+ $cachedFile->putContent($list);
}
- if (strlen($data) > 0) {
- if (!$cachedFile) {
- $cachedFile = $this->folder->newFile($this->fileName);
+ return preg_replace($this->iconVarRE, '', $css);
+ }
+
+ /**
+ * @param $url
+ * @return array
+ */
+ private function parseUrl($url): array {
+ $location = '';
+ $color = '';
+ $base = $this->getRoutePrefix() . '/svg/';
+ $cleanUrl = \substr($url, \strlen($base));
+ if (\strpos($url, $base . 'core') === 0) {
+ $cleanUrl = \substr($cleanUrl, \strlen('core'));
+ if (\preg_match('/\/([a-zA-Z0-9-_\~\/\.\=\:\;\+\,]+)\?color=([0-9a-fA-F]{3,6})/', $cleanUrl, $matches)) {
+ list(,$cleanUrl,$color) = $matches;
+ $location = \OC::$SERVERROOT . '/core/img/' . $cleanUrl . '.svg';
+ }
+ } elseif (\strpos($url, $base) === 0) {
+ if(\preg_match('/([A-z0-9\_\-]+)\/([a-zA-Z0-9-_\~\/\.\=\:\;\+\,]+)\?color=([0-9a-fA-F]{3,6})/', $cleanUrl, $matches)) {
+ list(,$app,$cleanUrl, $color) = $matches;
+ $location = \OC_App::getAppPath($app) . '/img/' . $cleanUrl . '.svg';
+ if ($app === 'settings') {
+ $location = \OC::$SERVERROOT . '/settings/img/' . $cleanUrl . '.svg';
+ }
}
- $data = ":root {
- $data
- }";
- $cachedFile->putContent($data);
}
+ return [
+ $location,
+ $color
+ ];
+ }
- return preg_replace($this->iconVarRE, '', $css);
+ /**
+ * @param $svg
+ * @param $color
+ * @return string
+ */
+ public function colorizeSvg($svg, $color): string {
+ // add fill (fill is not present on black elements)
+ $fillRe = '/<((circle|rect|path)((?!fill)[a-z0-9 =".\-#():;])+)\/>/mi';
+ $svg = preg_replace($fillRe, '<$1 fill="#' . $color . '"/>', $svg);
+
+ // replace any fill or stroke colors
+ $svg = preg_replace('/stroke="#([a-z0-9]{3,6})"/mi', 'stroke="#' . $color . '"', $svg);
+ $svg = preg_replace('/fill="#([a-z0-9]{3,6})"/mi', 'fill="#' . $color . '"', $svg);
+ return $svg;
+ }
+
+ private function getRoutePrefix() {
+ $frontControllerActive = (\OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true');
+ $prefix = \OC::$WEBROOT . '/index.php';
+ if ($frontControllerActive) {
+ $prefix = \OC::$WEBROOT;
+ }
+ return $prefix;
}
/**
@@ -130,6 +203,18 @@ class IconsCacher {
}
}
+ /**
+ * Get icon-vars list template
+ * @return ISimpleFile|boolean
+ */
+ public function getCachedList() {
+ try {
+ return $this->folder->getFile($this->iconList);
+ } catch (NotFoundException $e) {
+ return false;
+ }
+ }
+
public function injectCss() {
// Only inject once
foreach (\OC_Util::$headers as $header) {
diff --git a/lib/private/Template/JSConfigHelper.php b/lib/private/Template/JSConfigHelper.php
index b691a8a64cb..ad9ff0b6757 100644
--- a/lib/private/Template/JSConfigHelper.php
+++ b/lib/private/Template/JSConfigHelper.php
@@ -70,6 +70,9 @@ class JSConfigHelper {
/** @var CapabilitiesManager */
private $capabilitiesManager;
+ /** @var array user back-ends excluded from password verification */
+ private $excludedUserBackEnds = ['user_saml' => true, 'user_globalsiteselector' => true];
+
/**
* @param IL10N $l
* @param Defaults $defaults
@@ -158,7 +161,7 @@ class JSConfigHelper {
$array = [
"oc_debug" => $this->config->getSystemValue('debug', false) ? 'true' : 'false',
"oc_isadmin" => $this->groupManager->isAdmin($uid) ? 'true' : 'false',
- "backendAllowsPasswordConfirmation" => $userBackend === 'user_saml'? 'false' : 'true',
+ "backendAllowsPasswordConfirmation" => !isset($this->excludedUserBackEnds[$userBackend]) ? 'true' : 'false',
"oc_dataURL" => is_string($dataLocation) ? "\"".$dataLocation."\"" : 'false',
"oc_webroot" => "\"".\OC::$WEBROOT."\"",
"oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index a9c638dca93..674f38e2401 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -38,6 +38,7 @@
namespace OC\User;
use OC;
+use OC\Authentication\Exceptions\ExpiredTokenException;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
use OC\Authentication\Exceptions\PasswordLoginForbiddenException;
@@ -401,7 +402,13 @@ class Session implements IUserSession, Emitter {
$this->manager->emit('\OC\User', 'preLogin', array($user, $password));
}
- $isTokenPassword = $this->isTokenPassword($password);
+ try {
+ $isTokenPassword = $this->isTokenPassword($password);
+ } catch (ExpiredTokenException $e) {
+ // Just return on an expired token no need to check further or record a failed login
+ return false;
+ }
+
if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
throw new PasswordLoginForbiddenException();
}
@@ -474,11 +481,14 @@ class Session implements IUserSession, Emitter {
*
* @param string $password
* @return boolean
+ * @throws ExpiredTokenException
*/
public function isTokenPassword($password) {
try {
$this->tokenProvider->getToken($password);
return true;
+ } catch (ExpiredTokenException $e) {
+ throw $e;
} catch (InvalidTokenException $ex) {
return false;
}