diff options
Diffstat (limited to 'apps/files_sharing/lib/external')
-rw-r--r-- | apps/files_sharing/lib/external/cache.php | 65 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/manager.php | 419 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/mount.php | 70 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/mountprovider.php | 76 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/scanner.php | 127 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/storage.php | 323 |
6 files changed, 0 insertions, 1080 deletions
diff --git a/apps/files_sharing/lib/external/cache.php b/apps/files_sharing/lib/external/cache.php deleted file mode 100644 index da9bf83cdfa..00000000000 --- a/apps/files_sharing/lib/external/cache.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php -/** - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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 OCA\Files_Sharing\External; - -class Cache extends \OC\Files\Cache\Cache { - private $remote; - private $remoteUser; - private $storage; - - /** - * @param \OCA\Files_Sharing\External\Storage $storage - * @param string $remote - * @param string $remoteUser - */ - public function __construct($storage, $remote, $remoteUser) { - $this->storage = $storage; - list(, $remote) = explode('://', $remote, 2); - $this->remote = $remote; - $this->remoteUser = $remoteUser; - parent::__construct($storage); - } - - public function get($file) { - $result = parent::get($file); - if (!$result) { - return false; - } - $result['displayname_owner'] = $this->remoteUser . '@' . $this->remote; - if (!$file || $file === '') { - $result['is_share_mount_point'] = true; - $mountPoint = rtrim($this->storage->getMountPoint()); - $result['name'] = basename($mountPoint); - } - return $result; - } - - public function getFolderContentsById($id) { - $results = parent::getFolderContentsById($id); - foreach ($results as &$file) { - $file['displayname_owner'] = $this->remoteUser . '@' . $this->remote; - } - return $results; - } -} diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php deleted file mode 100644 index 71d6788cb52..00000000000 --- a/apps/files_sharing/lib/external/manager.php +++ /dev/null @@ -1,419 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Joas Schilling <nickvergessen@owncloud.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Roeland Jago Douma <rullzer@owncloud.com> - * - * @copyright Copyright (c) 2016, 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 OCA\Files_Sharing\External; - -use OC\Files\Filesystem; -use OCA\FederatedFileSharing\DiscoveryManager; -use OCP\Files; -use OCP\Notification\IManager; - -class Manager { - const STORAGE = '\OCA\Files_Sharing\External\Storage'; - - /** - * @var string - */ - private $uid; - - /** - * @var \OCP\IDBConnection - */ - private $connection; - - /** - * @var \OC\Files\Mount\Manager - */ - private $mountManager; - - /** - * @var \OCP\Files\Storage\IStorageFactory - */ - private $storageLoader; - - /** - * @var \OC\HTTPHelper - */ - private $httpHelper; - - /** - * @var IManager - */ - private $notificationManager; - /** @var DiscoveryManager */ - private $discoveryManager; - - /** - * @param \OCP\IDBConnection $connection - * @param \OC\Files\Mount\Manager $mountManager - * @param \OCP\Files\Storage\IStorageFactory $storageLoader - * @param \OC\HTTPHelper $httpHelper - * @param IManager $notificationManager - * @param DiscoveryManager $discoveryManager - * @param string $uid - */ - public function __construct(\OCP\IDBConnection $connection, - \OC\Files\Mount\Manager $mountManager, - \OCP\Files\Storage\IStorageFactory $storageLoader, - \OC\HTTPHelper $httpHelper, - IManager $notificationManager, - DiscoveryManager $discoveryManager, - $uid) { - $this->connection = $connection; - $this->mountManager = $mountManager; - $this->storageLoader = $storageLoader; - $this->httpHelper = $httpHelper; - $this->uid = $uid; - $this->notificationManager = $notificationManager; - $this->discoveryManager = $discoveryManager; - } - - /** - * add new server-to-server share - * - * @param string $remote - * @param string $token - * @param string $password - * @param string $name - * @param string $owner - * @param boolean $accepted - * @param string $user - * @param int $remoteId - * @return Mount|null - */ - public function addShare($remote, $token, $password, $name, $owner, $accepted=false, $user = null, $remoteId = -1) { - - $user = $user ? $user : $this->uid; - $accepted = $accepted ? 1 : 0; - $name = Filesystem::normalizePath('/' . $name); - - if (!$accepted) { - // To avoid conflicts with the mount point generation later, - // we only use a temporary mount point name here. The real - // mount point name will be generated when accepting the share, - // using the original share item name. - $tmpMountPointName = '{{TemporaryMountPointName#' . $name . '}}'; - $mountPoint = $tmpMountPointName; - $hash = md5($tmpMountPointName); - $data = [ - 'remote' => $remote, - 'share_token' => $token, - 'password' => $password, - 'name' => $name, - 'owner' => $owner, - 'user' => $user, - 'mountpoint' => $mountPoint, - 'mountpoint_hash' => $hash, - 'accepted' => $accepted, - 'remote_id' => $remoteId, - ]; - - $i = 1; - while (!$this->connection->insertIfNotExist('*PREFIX*share_external', $data, ['user', 'mountpoint_hash'])) { - // The external share already exists for the user - $data['mountpoint'] = $tmpMountPointName . '-' . $i; - $data['mountpoint_hash'] = md5($data['mountpoint']); - $i++; - } - return null; - } - - $mountPoint = Files::buildNotExistingFileName('/', $name); - $mountPoint = Filesystem::normalizePath('/' . $mountPoint); - $hash = md5($mountPoint); - - $query = $this->connection->prepare(' - INSERT INTO `*PREFIX*share_external` - (`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - '); - $query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId)); - - $options = array( - 'remote' => $remote, - 'token' => $token, - 'password' => $password, - 'mountpoint' => $mountPoint, - 'owner' => $owner - ); - return $this->mountShare($options); - } - - /** - * get share - * - * @param int $id share id - * @return mixed share of false - */ - public function getShare($id) { - $getShare = $this->connection->prepare(' - SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted` - FROM `*PREFIX*share_external` - WHERE `id` = ? AND `user` = ?'); - $result = $getShare->execute(array($id, $this->uid)); - - return $result ? $getShare->fetch() : false; - } - - /** - * accept server-to-server share - * - * @param int $id - * @return bool True if the share could be accepted, false otherwise - */ - public function acceptShare($id) { - - $share = $this->getShare($id); - - if ($share) { - $mountPoint = Files::buildNotExistingFileName('/', $share['name']); - $mountPoint = Filesystem::normalizePath('/' . $mountPoint); - $hash = md5($mountPoint); - - $acceptShare = $this->connection->prepare(' - UPDATE `*PREFIX*share_external` - SET `accepted` = ?, - `mountpoint` = ?, - `mountpoint_hash` = ? - WHERE `id` = ? AND `user` = ?'); - $acceptShare->execute(array(1, $mountPoint, $hash, $id, $this->uid)); - $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'accept'); - - \OC_Hook::emit('OCP\Share', 'federated_share_added', ['server' => $share['remote']]); - - $this->processNotification($id); - return true; - } - - return false; - } - - /** - * decline server-to-server share - * - * @param int $id - * @return bool True if the share could be declined, false otherwise - */ - public function declineShare($id) { - - $share = $this->getShare($id); - - if ($share) { - $removeShare = $this->connection->prepare(' - DELETE FROM `*PREFIX*share_external` WHERE `id` = ? AND `user` = ?'); - $removeShare->execute(array($id, $this->uid)); - $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline'); - - $this->processNotification($id); - return true; - } - - return false; - } - - /** - * @param int $remoteShare - */ - public function processNotification($remoteShare) { - $filter = $this->notificationManager->createNotification(); - $filter->setApp('files_sharing') - ->setUser($this->uid) - ->setObject('remote_share', (int) $remoteShare); - $this->notificationManager->markProcessed($filter); - } - - /** - * inform remote server whether server-to-server share was accepted/declined - * - * @param string $remote - * @param string $token - * @param int $remoteId Share id on the remote host - * @param string $feedback - * @return boolean - */ - private function sendFeedbackToRemote($remote, $token, $remoteId, $feedback) { - - $url = rtrim($remote, '/') . $this->discoveryManager->getShareEndpoint($remote) . '/' . $remoteId . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT; - $fields = array('token' => $token); - - $result = $this->httpHelper->post($url, $fields); - $status = json_decode($result['result'], true); - - return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200)); - } - - /** - * remove '/user/files' from the path and trailing slashes - * - * @param string $path - * @return string - */ - protected function stripPath($path) { - $prefix = '/' . $this->uid . '/files'; - return rtrim(substr($path, strlen($prefix)), '/'); - } - - public function getMount($data) { - $data['manager'] = $this; - $mountPoint = '/' . $this->uid . '/files' . $data['mountpoint']; - $data['mountpoint'] = $mountPoint; - $data['certificateManager'] = \OC::$server->getCertificateManager($this->uid); - return new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader); - } - - /** - * @param array $data - * @return Mount - */ - protected function mountShare($data) { - $mount = $this->getMount($data); - $this->mountManager->addMount($mount); - return $mount; - } - - /** - * @return \OC\Files\Mount\Manager - */ - public function getMountManager() { - return $this->mountManager; - } - - /** - * @param string $source - * @param string $target - * @return bool - */ - public function setMountPoint($source, $target) { - $source = $this->stripPath($source); - $target = $this->stripPath($target); - $sourceHash = md5($source); - $targetHash = md5($target); - - $query = $this->connection->prepare(' - UPDATE `*PREFIX*share_external` - SET `mountpoint` = ?, `mountpoint_hash` = ? - WHERE `mountpoint_hash` = ? - AND `user` = ? - '); - $result = (bool)$query->execute(array($target, $targetHash, $sourceHash, $this->uid)); - - return $result; - } - - public function removeShare($mountPoint) { - $mountPoint = $this->stripPath($mountPoint); - $hash = md5($mountPoint); - - $getShare = $this->connection->prepare(' - SELECT `remote`, `share_token`, `remote_id` - FROM `*PREFIX*share_external` - WHERE `mountpoint_hash` = ? AND `user` = ?'); - $result = $getShare->execute(array($hash, $this->uid)); - - if ($result) { - $share = $getShare->fetch(); - $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline'); - } - - $query = $this->connection->prepare(' - DELETE FROM `*PREFIX*share_external` - WHERE `mountpoint_hash` = ? - AND `user` = ? - '); - return (bool)$query->execute(array($hash, $this->uid)); - } - - /** - * remove all shares for user $uid if the user was deleted - * - * @param string $uid - * @return bool - */ - public function removeUserShares($uid) { - $getShare = $this->connection->prepare(' - SELECT `remote`, `share_token`, `remote_id` - FROM `*PREFIX*share_external` - WHERE `user` = ?'); - $result = $getShare->execute(array($uid)); - - if ($result) { - $shares = $getShare->fetchAll(); - foreach($shares as $share) { - $this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline'); - } - } - - $query = $this->connection->prepare(' - DELETE FROM `*PREFIX*share_external` - WHERE `user` = ? - '); - return (bool)$query->execute(array($uid)); - } - - /** - * return a list of shares which are not yet accepted by the user - * - * @return array list of open server-to-server shares - */ - public function getOpenShares() { - return $this->getShares(false); - } - - /** - * return a list of shares wich are accepted by the user - * - * @return array list of accepted server-to-server shares - */ - public function getAcceptedShares() { - return $this->getShares(true); - } - - /** - * return a list of shares for the user - * - * @param bool|null $accepted True for accepted only, - * false for not accepted, - * null for all shares of the user - * @return array list of open server-to-server shares - */ - private function getShares($accepted) { - $query = 'SELECT `id`, `remote`, `remote_id`, `share_token`, `name`, `owner`, `user`, `mountpoint`, `accepted` - FROM `*PREFIX*share_external` - WHERE `user` = ?'; - $parameters = [$this->uid]; - if (!is_null($accepted)) { - $query .= ' AND `accepted` = ?'; - $parameters[] = (int) $accepted; - } - $query .= ' ORDER BY `id` ASC'; - - $shares = $this->connection->prepare($query); - $result = $shares->execute($parameters); - - return $result ? $shares->fetchAll() : []; - } -} diff --git a/apps/files_sharing/lib/external/mount.php b/apps/files_sharing/lib/external/mount.php deleted file mode 100644 index 9cf66d3f8f0..00000000000 --- a/apps/files_sharing/lib/external/mount.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** - * @author Björn Schießle <schiessle@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, 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 OCA\Files_Sharing\External; - -use OC\Files\Mount\MountPoint; -use OC\Files\Mount\MoveableMount; - -class Mount extends MountPoint implements MoveableMount { - - /** - * @var \OCA\Files_Sharing\External\Manager - */ - protected $manager; - - /** - * @param string|\OC\Files\Storage\Storage $storage - * @param string $mountpoint - * @param array $options - * @param \OCA\Files_Sharing\External\Manager $manager - * @param \OC\Files\Storage\StorageFactory $loader - */ - public function __construct($storage, $mountpoint, $options, $manager, $loader = null) { - parent::__construct($storage, $mountpoint, $options, $loader); - $this->manager = $manager; - } - - /** - * Move the mount point to $target - * - * @param string $target the target mount point - * @return bool - */ - public function moveMount($target) { - $result = $this->manager->setMountPoint($this->mountPoint, $target); - $this->setMountPoint($target); - - return $result; - } - - /** - * Remove the mount points - * - * @return mixed - * @return bool - */ - public function removeMount() { - return $this->manager->removeShare($this->mountPoint); - } -} diff --git a/apps/files_sharing/lib/external/mountprovider.php b/apps/files_sharing/lib/external/mountprovider.php deleted file mode 100644 index 67d85f27d81..00000000000 --- a/apps/files_sharing/lib/external/mountprovider.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php -/** - * @author Robin Appelman <icewind@owncloud.com> - * - * @copyright Copyright (c) 2016, 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 OCA\Files_Sharing\External; - -use OCP\Files\Config\IMountProvider; -use OCP\Files\Storage\IStorageFactory; -use OCP\IDBConnection; -use OCP\IUser; - -class MountProvider implements IMountProvider { - const STORAGE = '\OCA\Files_Sharing\External\Storage'; - - /** - * @var \OCP\IDBConnection - */ - private $connection; - - /** - * @var callable - */ - private $managerProvider; - - /** - * @param \OCP\IDBConnection $connection - * @param callable $managerProvider due to setup order we need a callable that return the manager instead of the manager itself - */ - public function __construct(IDBConnection $connection, callable $managerProvider) { - $this->connection = $connection; - $this->managerProvider = $managerProvider; - } - - public function getMount(IUser $user, $data, IStorageFactory $storageFactory) { - $managerProvider = $this->managerProvider; - $manager = $managerProvider(); - $data['manager'] = $manager; - $mountPoint = '/' . $user->getUID() . '/files/' . ltrim($data['mountpoint'], '/'); - $data['mountpoint'] = $mountPoint; - $data['certificateManager'] = \OC::$server->getCertificateManager($user->getUID()); - return new Mount(self::STORAGE, $mountPoint, $data, $manager, $storageFactory); - } - - public function getMountsForUser(IUser $user, IStorageFactory $loader) { - $query = $this->connection->prepare(' - SELECT `remote`, `share_token`, `password`, `mountpoint`, `owner` - FROM `*PREFIX*share_external` - WHERE `user` = ? AND `accepted` = ? - '); - $query->execute([$user->getUID(), 1]); - $mounts = []; - while ($row = $query->fetch()) { - $row['manager'] = $this; - $row['token'] = $row['share_token']; - $mounts[] = $this->getMount($user, $row, $loader); - } - return $mounts; - } -} diff --git a/apps/files_sharing/lib/external/scanner.php b/apps/files_sharing/lib/external/scanner.php deleted file mode 100644 index 1cc6cf8f5f9..00000000000 --- a/apps/files_sharing/lib/external/scanner.php +++ /dev/null @@ -1,127 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <icewind@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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 OCA\Files_Sharing\External; - -use OC\ForbiddenException; -use OCP\Files\NotFoundException; -use OCP\Files\StorageInvalidException; -use OCP\Files\StorageNotAvailableException; - -class Scanner extends \OC\Files\Cache\Scanner { - /** @var \OCA\Files_Sharing\External\Storage */ - protected $storage; - - /** {@inheritDoc} */ - public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true) { - if(!$this->storage->remoteIsOwnCloud()) { - return parent::scan($path, $recursive, $recursive, $lock); - } - - $this->scanAll(); - } - - /** - * Scan a single file and store it in the cache. - * If an exception happened while accessing the external storage, - * the storage will be checked for availability and removed - * if it is not available any more. - * - * @param string $file file to scan - * @param int $reuseExisting - * @param int $parentId - * @param array | null $cacheData existing data in the cache for the file to be scanned - * @param bool $lock set to false to disable getting an additional read lock during scanning - * @return array an array of metadata of the scanned file - */ - public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) { - try { - return parent::scanFile($file, $reuseExisting); - } catch (ForbiddenException $e) { - $this->storage->checkStorageAvailability(); - } catch (NotFoundException $e) { - // if the storage isn't found, the call to - // checkStorageAvailable() will verify it and remove it - // if appropriate - $this->storage->checkStorageAvailability(); - } catch (StorageInvalidException $e) { - $this->storage->checkStorageAvailability(); - } catch (StorageNotAvailableException $e) { - $this->storage->checkStorageAvailability(); - } - } - - /** - * Checks the remote share for changes. - * If changes are available, scan them and update - * the cache. - * @throws NotFoundException - * @throws StorageInvalidException - * @throws \Exception - */ - public function scanAll() { - try { - $data = $this->storage->getShareInfo(); - } catch (\Exception $e) { - $this->storage->checkStorageAvailability(); - throw new \Exception( - 'Error while scanning remote share: "' . - $this->storage->getRemote() . '" ' . - $e->getMessage() - ); - } - if ($data['status'] === 'success') { - $this->addResult($data['data'], ''); - } else { - throw new \Exception( - 'Error while scanning remote share: "' . - $this->storage->getRemote() . '"' - ); - } - } - - /** - * @param array $data - * @param string $path - */ - private function addResult($data, $path) { - $id = $this->cache->put($path, $data); - if (isset($data['children'])) { - $children = []; - foreach ($data['children'] as $child) { - $children[$child['name']] = true; - $this->addResult($child, ltrim($path . '/' . $child['name'], '/')); - } - - $existingCache = $this->cache->getFolderContentsById($id); - foreach ($existingCache as $existingChild) { - // if an existing child is not in the new data, remove it - if (!isset($children[$existingChild['name']])) { - $this->cache->remove(ltrim($path . '/' . $existingChild['name'], '/')); - } - } - } - } -} diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php deleted file mode 100644 index 8fe7af66044..00000000000 --- a/apps/files_sharing/lib/external/storage.php +++ /dev/null @@ -1,323 +0,0 @@ -<?php -/** - * @author Lukas Reschke <lukas@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <icewind@owncloud.com> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @copyright Copyright (c) 2016, 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 OCA\Files_Sharing\External; - -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Exception\ConnectException; -use OC\Files\Storage\DAV; -use OC\ForbiddenException; -use OCA\FederatedFileSharing\DiscoveryManager; -use OCA\Files_Sharing\ISharedStorage; -use OCP\Files\NotFoundException; -use OCP\Files\StorageInvalidException; -use OCP\Files\StorageNotAvailableException; - -class Storage extends DAV implements ISharedStorage { - /** @var string */ - private $remoteUser; - /** @var string */ - private $remote; - /** @var string */ - private $mountPoint; - /** @var string */ - private $token; - /** @var \OCP\ICacheFactory */ - private $memcacheFactory; - /** @var \OCP\Http\Client\IClientService */ - private $httpClient; - /** @var \OCP\ICertificateManager */ - private $certificateManager; - /** @var bool */ - private $updateChecked = false; - - /** - * @var \OCA\Files_Sharing\External\Manager - */ - private $manager; - - public function __construct($options) { - $this->memcacheFactory = \OC::$server->getMemCacheFactory(); - $this->httpClient = \OC::$server->getHTTPClientService(); - $discoveryManager = new DiscoveryManager( - $this->memcacheFactory, - \OC::$server->getHTTPClientService() - ); - - $this->manager = $options['manager']; - $this->certificateManager = $options['certificateManager']; - $this->remote = $options['remote']; - $this->remoteUser = $options['owner']; - list($protocol, $remote) = explode('://', $this->remote); - if (strpos($remote, '/')) { - list($host, $root) = explode('/', $remote, 2); - } else { - $host = $remote; - $root = ''; - } - $secure = $protocol === 'https'; - $root = rtrim($root, '/') . $discoveryManager->getWebDavEndpoint($this->remote); - $this->mountPoint = $options['mountpoint']; - $this->token = $options['token']; - parent::__construct(array( - 'secure' => $secure, - 'host' => $host, - 'root' => $root, - 'user' => $options['token'], - 'password' => (string)$options['password'] - )); - - $this->getWatcher()->setPolicy(\OC\Files\Cache\Watcher::CHECK_ONCE); - } - - public function getRemoteUser() { - return $this->remoteUser; - } - - public function getRemote() { - return $this->remote; - } - - public function getMountPoint() { - return $this->mountPoint; - } - - public function getToken() { - return $this->token; - } - - public function getPassword() { - return $this->password; - } - - /** - * @brief get id of the mount point - * @return string - */ - public function getId() { - return 'shared::' . md5($this->token . '@' . $this->remote); - } - - public function getCache($path = '', $storage = null) { - if (is_null($this->cache)) { - $this->cache = new Cache($this, $this->remote, $this->remoteUser); - } - return $this->cache; - } - - /** - * @param string $path - * @param \OC\Files\Storage\Storage $storage - * @return \OCA\Files_Sharing\External\Scanner - */ - public function getScanner($path = '', $storage = null) { - if (!$storage) { - $storage = $this; - } - if (!isset($this->scanner)) { - $this->scanner = new Scanner($storage); - } - return $this->scanner; - } - - /** - * check if a file or folder has been updated since $time - * - * @param string $path - * @param int $time - * @throws \OCP\Files\StorageNotAvailableException - * @throws \OCP\Files\StorageInvalidException - * @return bool - */ - public function hasUpdated($path, $time) { - // since for owncloud webdav servers we can rely on etag propagation we only need to check the root of the storage - // because of that we only do one check for the entire storage per request - if ($this->updateChecked) { - return false; - } - $this->updateChecked = true; - try { - return parent::hasUpdated('', $time); - } catch (StorageInvalidException $e) { - // check if it needs to be removed - $this->checkStorageAvailability(); - throw $e; - } catch (StorageNotAvailableException $e) { - // check if it needs to be removed or just temp unavailable - $this->checkStorageAvailability(); - throw $e; - } - } - - /** - * Check whether this storage is permanently or temporarily - * unavailable - * - * @throws \OCP\Files\StorageNotAvailableException - * @throws \OCP\Files\StorageInvalidException - */ - public function checkStorageAvailability() { - // see if we can find out why the share is unavailable - try { - $this->getShareInfo(); - } catch (NotFoundException $e) { - // a 404 can either mean that the share no longer exists or there is no ownCloud on the remote - if ($this->testRemote()) { - // valid ownCloud instance means that the public share no longer exists - // since this is permanent (re-sharing the file will create a new token) - // we remove the invalid storage - $this->manager->removeShare($this->mountPoint); - $this->manager->getMountManager()->removeMount($this->mountPoint); - throw new StorageInvalidException(); - } else { - // ownCloud instance is gone, likely to be a temporary server configuration error - throw new StorageNotAvailableException(); - } - } catch (ForbiddenException $e) { - // auth error, remove share for now (provide a dialog in the future) - $this->manager->removeShare($this->mountPoint); - $this->manager->getMountManager()->removeMount($this->mountPoint); - throw new StorageInvalidException(); - } catch (\GuzzleHttp\Exception\ConnectException $e) { - throw new StorageNotAvailableException(); - } catch (\GuzzleHttp\Exception\RequestException $e) { - throw new StorageNotAvailableException(); - } catch (\Exception $e) { - throw $e; - } - } - - public function file_exists($path) { - if ($path === '') { - return true; - } else { - return parent::file_exists($path); - } - } - - /** - * check if the configured remote is a valid federated share provider - * - * @return bool - */ - protected function testRemote() { - try { - return $this->testRemoteUrl($this->remote . '/ocs-provider/index.php') - || $this->testRemoteUrl($this->remote . '/ocs-provider/') - || $this->testRemoteUrl($this->remote . '/status.php'); - } catch (\Exception $e) { - return false; - } - } - - /** - * @param string $url - * @return bool - */ - private function testRemoteUrl($url) { - $cache = $this->memcacheFactory->create('files_sharing_remote_url'); - if($cache->hasKey($url)) { - return (bool)$cache->get($url); - } - - $client = $this->httpClient->newClient(); - try { - $result = $client->get($url)->getBody(); - $data = json_decode($result); - $returnValue = (is_object($data) && !empty($data->version)); - } catch (ConnectException $e) { - $returnValue = false; - } catch (ClientException $e) { - $returnValue = false; - } - - $cache->set($url, $returnValue); - return $returnValue; - } - - /** - * Whether the remote is an ownCloud, used since some sharing features are not - * standardized. Let's use this to detect whether to use it. - * - * @return bool - */ - public function remoteIsOwnCloud() { - if(defined('PHPUNIT_RUN') || !$this->testRemoteUrl($this->getRemote() . '/status.php')) { - return false; - } - return true; - } - - /** - * @return mixed - * @throws ForbiddenException - * @throws NotFoundException - * @throws \Exception - */ - public function getShareInfo() { - $remote = $this->getRemote(); - $token = $this->getToken(); - $password = $this->getPassword(); - - // If remote is not an ownCloud do not try to get any share info - if(!$this->remoteIsOwnCloud()) { - return ['status' => 'unsupported']; - } - - $url = rtrim($remote, '/') . '/index.php/apps/files_sharing/shareinfo?t=' . $token; - - // TODO: DI - $client = \OC::$server->getHTTPClientService()->newClient(); - try { - $response = $client->post($url, ['body' => ['password' => $password]]); - } catch (\GuzzleHttp\Exception\RequestException $e) { - if ($e->getCode() === 401 || $e->getCode() === 403) { - throw new ForbiddenException(); - } - if ($e->getCode() === 404) { - throw new NotFoundException(); - } - // throw this to be on the safe side: the share will still be visible - // in the UI in case the failure is intermittent, and the user will - // be able to decide whether to remove it if it's really gone - throw new StorageNotAvailableException(); - } - - return json_decode($response->getBody(), true); - } - - public function getOwner($path) { - list(, $remote) = explode('://', $this->remote, 2); - return $this->remoteUser . '@' . $remote; - } - - public function isSharable($path) { - if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) { - return false; - } - return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE); - } - -} |