Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_sharing/lib/External/Manager.php')
-rw-r--r--apps/files_sharing/lib/External/Manager.php330
1 files changed, 251 insertions, 79 deletions
diff --git a/apps/files_sharing/lib/External/Manager.php b/apps/files_sharing/lib/External/Manager.php
index 534dd0d2c51..a48e2a63ae4 100644
--- a/apps/files_sharing/lib/External/Manager.php
+++ b/apps/files_sharing/lib/External/Manager.php
@@ -14,6 +14,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Stefan Weil <sw@weilnetz.de>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -37,6 +38,7 @@ use Doctrine\DBAL\Driver\Exception;
use OC\Files\Filesystem;
use OCA\FederatedFileSharing\Events\FederatedShareAddedEvent;
use OCA\Files_Sharing\Helper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager;
@@ -46,10 +48,12 @@ use OCP\Http\Client\IClientService;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IUserManager;
+use OCP\IUserSession;
use OCP\Notification\IManager;
use OCP\OCS\IDiscoveryService;
use OCP\Share;
use OCP\Share\IShare;
+use Psr\Log\LoggerInterface;
class Manager {
public const STORAGE = '\OCA\Files_Sharing\External\Storage';
@@ -81,7 +85,7 @@ class Manager {
/** @var ICloudFederationFactory */
private $cloudFederationFactory;
- /** @var IGroupManager */
+ /** @var IGroupManager */
private $groupManager;
/** @var IUserManager */
@@ -90,23 +94,30 @@ class Manager {
/** @var IEventDispatcher */
private $eventDispatcher;
- public function __construct(IDBConnection $connection,
- \OC\Files\Mount\Manager $mountManager,
- IStorageFactory $storageLoader,
- IClientService $clientService,
- IManager $notificationManager,
- IDiscoveryService $discoveryService,
- ICloudFederationProviderManager $cloudFederationProviderManager,
- ICloudFederationFactory $cloudFederationFactory,
- IGroupManager $groupManager,
- IUserManager $userManager,
- ?string $uid,
- IEventDispatcher $eventDispatcher) {
+ /** @var LoggerInterface */
+ private $logger;
+
+ public function __construct(
+ IDBConnection $connection,
+ \OC\Files\Mount\Manager $mountManager,
+ IStorageFactory $storageLoader,
+ IClientService $clientService,
+ IManager $notificationManager,
+ IDiscoveryService $discoveryService,
+ ICloudFederationProviderManager $cloudFederationProviderManager,
+ ICloudFederationFactory $cloudFederationFactory,
+ IGroupManager $groupManager,
+ IUserManager $userManager,
+ IUserSession $userSession,
+ IEventDispatcher $eventDispatcher,
+ LoggerInterface $logger
+ ) {
+ $user = $userSession->getUser();
$this->connection = $connection;
$this->mountManager = $mountManager;
$this->storageLoader = $storageLoader;
$this->clientService = $clientService;
- $this->uid = $uid;
+ $this->uid = $user ? $user->getUID() : null;
$this->notificationManager = $notificationManager;
$this->discoveryService = $discoveryService;
$this->cloudFederationProviderManager = $cloudFederationProviderManager;
@@ -114,6 +125,7 @@ class Manager {
$this->groupManager = $groupManager;
$this->userManager = $userManager;
$this->eventDispatcher = $eventDispatcher;
+ $this->logger = $logger;
}
/**
@@ -219,7 +231,7 @@ class Manager {
* @param int $id share id
* @return mixed share of false
*/
- public function getShare($id) {
+ private function fetchShare($id) {
$getShare = $this->connection->prepare('
SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted`, `parent`, `share_type`, `password`, `mountpoint_hash`
FROM `*PREFIX*share_external`
@@ -227,14 +239,46 @@ class Manager {
$result = $getShare->execute([$id]);
$share = $result->fetch();
$result->closeCursor();
+ return $share;
+ }
+
+ private function fetchUserShare($parentId, $uid) {
+ $getShare = $this->connection->prepare('
+ SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted`, `parent`, `share_type`, `password`, `mountpoint_hash`
+ FROM `*PREFIX*share_external`
+ WHERE `parent` = ? AND `user` = ?');
+ $result = $getShare->execute([$parentId, $uid]);
+ $share = $result->fetch();
+ $result->closeCursor();
+ if ($share !== false) {
+ return $share;
+ }
+ return null;
+ }
+
+ /**
+ * get share
+ *
+ * @param int $id share id
+ * @return mixed share of false
+ */
+ public function getShare($id) {
+ $share = $this->fetchShare($id);
$validShare = is_array($share) && isset($share['share_type']) && isset($share['user']);
// check if the user is allowed to access it
if ($validShare && (int)$share['share_type'] === IShare::TYPE_USER && $share['user'] === $this->uid) {
return $share;
} elseif ($validShare && (int)$share['share_type'] === IShare::TYPE_GROUP) {
+ $parentId = (int)$share['parent'];
+ if ($parentId !== -1) {
+ // we just retrieved a sub-share, switch to the parent entry for verification
+ $groupShare = $this->fetchShare($parentId);
+ } else {
+ $groupShare = $share;
+ }
$user = $this->userManager->get($this->uid);
- if ($this->groupManager->get($share['user'])->inGroup($user)) {
+ if ($this->groupManager->get($groupShare['user'])->inGroup($user)) {
return $share;
}
}
@@ -243,6 +287,20 @@ class Manager {
}
/**
+ * Updates accepted flag in the database
+ *
+ * @param int $id
+ */
+ private function updateAccepted(int $shareId, bool $accepted) : void {
+ $query = $this->connection->prepare('
+ UPDATE `*PREFIX*share_external`
+ SET `accepted` = ?
+ WHERE `id` = ?');
+ $updateResult = $query->execute([$accepted ? 1 : 0, $shareId]);
+ $updateResult->closeCursor();
+ }
+
+ /**
* accept server-to-server share
*
* @param int $id
@@ -254,7 +312,7 @@ class Manager {
if ($share) {
\OC_Util::setupFS($this->uid);
- $shareFolder = Helper::getShareFolder();
+ $shareFolder = Helper::getShareFolder(null, $this->uid);
$mountPoint = Files::buildNotExistingFileName($shareFolder, $share['name']);
$mountPoint = Filesystem::normalizePath($mountPoint);
$hash = md5($mountPoint);
@@ -269,21 +327,46 @@ class Manager {
WHERE `id` = ? AND `user` = ?');
$userShareAccepted = $acceptShare->execute([1, $mountPoint, $hash, $id, $this->uid]);
} else {
- try {
- $this->writeShareToDb(
- $share['remote'],
- $share['share_token'],
- $share['password'],
- $share['name'],
- $share['owner'],
- $this->uid,
- $mountPoint, $hash, 1,
- $share['remote_id'],
- $id,
- $share['share_type']);
- $result = true;
- } catch (Exception $e) {
- $result = false;
+ $parentId = (int)$share['parent'];
+ if ($parentId !== -1) {
+ // this is the sub-share
+ $subshare = $share;
+ } else {
+ $subshare = $this->fetchUserShare($id, $this->uid);
+ }
+
+ if ($subshare !== null) {
+ try {
+ $acceptShare = $this->connection->prepare('
+ UPDATE `*PREFIX*share_external`
+ SET `accepted` = ?,
+ `mountpoint` = ?,
+ `mountpoint_hash` = ?
+ WHERE `id` = ? AND `user` = ?');
+ $acceptShare->execute([1, $mountPoint, $hash, $subshare['id'], $this->uid]);
+ $result = true;
+ } catch (Exception $e) {
+ $this->logger->emergency('Could not update share', ['exception' => $e]);
+ $result = false;
+ }
+ } else {
+ try {
+ $this->writeShareToDb(
+ $share['remote'],
+ $share['share_token'],
+ $share['password'],
+ $share['name'],
+ $share['owner'],
+ $this->uid,
+ $mountPoint, $hash, 1,
+ $share['remote_id'],
+ $id,
+ $share['share_type']);
+ $result = true;
+ } catch (Exception $e) {
+ $this->logger->emergency('Could not create share', ['exception' => $e]);
+ $result = false;
+ }
}
}
if ($userShareAccepted !== false) {
@@ -319,23 +402,42 @@ class Manager {
$this->processNotification($id);
$result = true;
} elseif ($share && (int)$share['share_type'] === IShare::TYPE_GROUP) {
- try {
- $this->writeShareToDb(
- $share['remote'],
- $share['share_token'],
- $share['password'],
- $share['name'],
- $share['owner'],
- $this->uid,
- $share['mountpoint'],
- $share['mountpoint_hash'],
- 0,
- $share['remote_id'],
- $id,
- $share['share_type']);
- $result = true;
- } catch (Exception $e) {
- $result = false;
+ $parentId = (int)$share['parent'];
+ if ($parentId !== -1) {
+ // this is the sub-share
+ $subshare = $share;
+ } else {
+ $subshare = $this->fetchUserShare($id, $this->uid);
+ }
+
+ if ($subshare !== null) {
+ try {
+ $this->updateAccepted((int)$subshare['id'], false);
+ $result = true;
+ } catch (Exception $e) {
+ $this->logger->emergency('Could not update share', ['exception' => $e]);
+ $result = false;
+ }
+ } else {
+ try {
+ $this->writeShareToDb(
+ $share['remote'],
+ $share['share_token'],
+ $share['password'],
+ $share['name'],
+ $share['owner'],
+ $this->uid,
+ $share['mountpoint'],
+ $share['mountpoint_hash'],
+ 0,
+ $share['remote_id'],
+ $id,
+ $share['share_type']);
+ $result = true;
+ } catch (Exception $e) {
+ $this->logger->emergency('Could not create share', ['exception' => $e]);
+ $result = false;
+ }
}
$this->processNotification($id);
}
@@ -366,7 +468,7 @@ class Manager {
private function sendFeedbackToRemote($remote, $token, $remoteId, $feedback) {
$result = $this->tryOCMEndPoint($remote, $token, $remoteId, $feedback);
- if ($result === true) {
+ if (is_array($result)) {
return true;
}
@@ -402,7 +504,7 @@ class Manager {
* @param string $token
* @param string $remoteId id of the share
* @param string $feedback
- * @return bool
+ * @return array|false
*/
protected function tryOCMEndPoint($remoteDomain, $token, $remoteId, $feedback) {
switch ($feedback) {
@@ -498,6 +600,10 @@ class Manager {
public function removeShare($mountPoint): bool {
$mountPointObj = $this->mountManager->find($mountPoint);
+ if ($mountPointObj === null) {
+ $this->logger->error('Mount point to remove share not found', ['mountPoint' => $mountPoint]);
+ return false;
+ }
$id = $mountPointObj->getStorage()->getCache()->getId('');
$mountPoint = $this->stripPath($mountPoint);
@@ -520,22 +626,18 @@ class Manager {
}
$query = $this->connection->prepare('
- DELETE FROM `*PREFIX*share_external`
- WHERE `id` = ?
+ DELETE FROM `*PREFIX*share_external`
+ WHERE `id` = ?
');
$deleteResult = $query->execute([(int)$share['id']]);
$deleteResult->closeCursor();
} elseif ($share !== false && (int)$share['share_type'] === IShare::TYPE_GROUP) {
- $query = $this->connection->prepare('
- UPDATE `*PREFIX*share_external`
- SET `accepted` = ?
- WHERE `id` = ?');
- $updateResult = $query->execute([0, (int)$share['id']]);
- $updateResult->closeCursor();
+ $this->updateAccepted((int)$share['id'], false);
}
$this->removeReShares($id);
} catch (\Doctrine\DBAL\Exception $ex) {
+ $this->logger->emergency('Could not update share', ['exception' => $ex]);
return false;
}
@@ -572,24 +674,73 @@ class Manager {
*/
public function removeUserShares($uid): bool {
try {
+ // TODO: use query builder
$getShare = $this->connection->prepare('
- SELECT `remote`, `share_token`, `remote_id`
+ SELECT `id`, `remote`, `share_type`, `share_token`, `remote_id`
FROM `*PREFIX*share_external`
- WHERE `user` = ?');
- $result = $getShare->execute([$uid]);
+ WHERE `user` = ?
+ AND `share_type` = ?');
+ $result = $getShare->execute([$uid, IShare::TYPE_USER]);
$shares = $result->fetchAll();
$result->closeCursor();
+
foreach ($shares as $share) {
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
}
- $query = $this->connection->prepare('
- DELETE FROM `*PREFIX*share_external`
+ $qb = $this->connection->getQueryBuilder();
+ $qb->delete('share_external')
+ // user field can specify a user or a group
+ ->where($qb->expr()->eq('user', $qb->createNamedParameter($uid)))
+ ->andWhere(
+ $qb->expr()->orX(
+ // delete direct shares
+ $qb->expr()->eq('share_type', $qb->expr()->literal(IShare::TYPE_USER)),
+ // delete sub-shares of group shares for that user
+ $qb->expr()->andX(
+ $qb->expr()->eq('share_type', $qb->expr()->literal(IShare::TYPE_GROUP)),
+ $qb->expr()->neq('parent', $qb->expr()->literal(-1)),
+ )
+ )
+ );
+ $qb->execute();
+ } catch (\Doctrine\DBAL\Exception $ex) {
+ $this->logger->emergency('Could not delete user shares', ['exception' => $ex]);
+ return false;
+ }
+
+ return true;
+ }
+
+ public function removeGroupShares($gid): bool {
+ try {
+ $getShare = $this->connection->prepare('
+ SELECT `id`, `remote`, `share_type`, `share_token`, `remote_id`
+ FROM `*PREFIX*share_external`
WHERE `user` = ?
- ');
- $deleteResult = $query->execute([$uid]);
- $deleteResult->closeCursor();
+ AND `share_type` = ?');
+ $result = $getShare->execute([$gid, IShare::TYPE_GROUP]);
+ $shares = $result->fetchAll();
+ $result->closeCursor();
+
+ $deletedGroupShares = [];
+ $qb = $this->connection->getQueryBuilder();
+ // delete group share entry and matching sub-entries
+ $qb->delete('share_external')
+ ->where(
+ $qb->expr()->orX(
+ $qb->expr()->eq('id', $qb->createParameter('share_id')),
+ $qb->expr()->eq('parent', $qb->createParameter('share_parent_id'))
+ )
+ );
+
+ foreach ($shares as $share) {
+ $qb->setParameter('share_id', $share['id']);
+ $qb->setParameter('share_parent_id', $share['id']);
+ $qb->execute();
+ }
} catch (\Doctrine\DBAL\Exception $ex) {
+ $this->logger->emergency('Could not delete user shares', ['exception' => $ex]);
return false;
}
@@ -630,23 +781,44 @@ class Manager {
$userGroups[] = $group->getGID();
}
- $query = 'SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted`
- FROM `*PREFIX*share_external`
- WHERE (`user` = ? OR `user` IN (?))';
- $parameters = [$this->uid, implode(',',$userGroups)];
- if (!is_null($accepted)) {
- $query .= ' AND `accepted` = ?';
- $parameters[] = (int) $accepted;
- }
- $query .= ' ORDER BY `id` ASC';
+ $qb = $this->connection->getQueryBuilder();
+ $qb->select('id', 'share_type', 'parent', 'remote', 'remote_id', 'share_token', 'name', 'owner', 'user', 'mountpoint', 'accepted')
+ ->from('share_external')
+ ->where(
+ $qb->expr()->orX(
+ $qb->expr()->eq('user', $qb->createNamedParameter($this->uid)),
+ $qb->expr()->in(
+ 'user',
+ $qb->createNamedParameter($userGroups, IQueryBuilder::PARAM_STR_ARRAY)
+ )
+ )
+ )
+ ->orderBy('id', 'ASC');
- $sharesQuery = $this->connection->prepare($query);
try {
- $result = $sharesQuery->execute($parameters);
+ $result = $qb->execute();
$shares = $result->fetchAll();
$result->closeCursor();
- return $shares;
+
+ // remove parent group share entry if we have a specific user share entry for the user
+ $toRemove = [];
+ foreach ($shares as $share) {
+ if ((int)$share['share_type'] === IShare::TYPE_GROUP && (int)$share['parent'] > 0) {
+ $toRemove[] = $share['parent'];
+ }
+ }
+ $shares = array_filter($shares, function ($share) use ($toRemove) {
+ return !in_array($share['id'], $toRemove, true);
+ });
+
+ if (!is_null($accepted)) {
+ $shares = array_filter($shares, function ($share) use ($accepted) {
+ return (bool)$share['accepted'] === $accepted;
+ });
+ }
+ return array_values($shares);
} catch (\Doctrine\DBAL\Exception $e) {
+ $this->logger->emergency('Error when retrieving shares', ['exception' => $e]);
return [];
}
}