/** * Get all mountpoints applicable for the user and check for shares where we need to update the etags * * @param \OCP\IUser $user * @param \OCP\Files\Storage\IStorageFactory $storageFactory * @return \OCP\Files\Mount\IMountPoint[] */ public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) { $shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1); $shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1)); $shares = array_filter($shares, function (\OCP\Share\IShare $share) { return $share->getPermissions() > 0; }); $mounts = []; foreach ($shares as $share) { $mounts[] = new SharedMount('\\OC\\Files\\Storage\\Shared', $mounts, ['user' => $user->getUID(), 'newShare' => $share], $storageFactory); } // array_filter removes the null values from the array return array_filter($mounts); }
/** * @param OutputInterface $output */ private function restoreShares(OutputInterface $output) { $output->writeln("Restoring shares ..."); $progress = new ProgressBar($output, count($this->shares)); foreach ($this->shares as $share) { if ($share->getSharedWith() === $this->destinationUser) { // Unmount the shares before deleting, so we don't try to get the storage later on. $shareMountPoint = $this->mountManager->find('/' . $this->destinationUser . '/files' . $share->getTarget()); if ($shareMountPoint) { $this->mountManager->removeMount($shareMountPoint->getMountPoint()); } $this->shareManager->deleteShare($share); } else { if ($share->getShareOwner() === $this->sourceUser) { $share->setShareOwner($this->destinationUser); } if ($share->getSharedBy() === $this->sourceUser) { $share->setSharedBy($this->destinationUser); } $this->shareManager->updateShare($share); } $progress->advance(); } $progress->finish(); $output->writeln(''); }
/** * Tests merging shares. * * Happens when sharing the same entry to a user through multiple ways, * like several groups and also direct shares at the same time. * * @dataProvider mergeSharesDataProvider * * @param array $userShares array of user share specs * @param array $groupShares array of group share specs * @param array $expectedShares array of expected supershare specs */ public function testMergeShares($userShares, $groupShares, $expectedShares) { $rootFolder = $this->getMock('\\OCP\\Files\\IRootFolder'); $userManager = $this->getMock('\\OCP\\IUserManager'); $userShares = array_map(function ($shareSpec) { return $this->makeMockShare($shareSpec[0], $shareSpec[1], $shareSpec[2], $shareSpec[3], $shareSpec[4]); }, $userShares); $groupShares = array_map(function ($shareSpec) { return $this->makeMockShare($shareSpec[0], $shareSpec[1], $shareSpec[2], $shareSpec[3], $shareSpec[4]); }, $groupShares); $this->user->expects($this->any())->method('getUID')->will($this->returnValue('user1')); $this->shareManager->expects($this->at(0))->method('getSharedWith')->with('user1', \OCP\Share::SHARE_TYPE_USER)->will($this->returnValue($userShares)); $this->shareManager->expects($this->at(1))->method('getSharedWith')->with('user1', \OCP\Share::SHARE_TYPE_GROUP, null, -1)->will($this->returnValue($groupShares)); $this->shareManager->expects($this->any())->method('newShare')->will($this->returnCallback(function () use($rootFolder, $userManager) { return new \OC\Share20\Share($rootFolder, $userManager); })); $mounts = $this->provider->getMountsForUser($this->user, $this->loader); $this->assertCount(count($expectedShares), $mounts); foreach ($mounts as $index => $mount) { $expectedShare = $expectedShares[$index]; $this->assertInstanceOf('OCA\\Files_Sharing\\SharedMount', $mount); // supershare $share = $mount->getShare(); $this->assertEquals($expectedShare[0], $share->getId()); $this->assertEquals($expectedShare[1], $share->getNodeId()); $this->assertEquals($expectedShare[2], $share->getShareOwner()); $this->assertEquals($expectedShare[3], $share->getTarget()); $this->assertEquals($expectedShare[4], $share->getPermissions()); } }
/** * @param int $type The share type * @param string $path The path to share relative to $initiators root * @param string $initiator * @param string $recipient * @param int $permissions * @return \OCP\Share\IShare */ protected function share($type, $path, $initiator, $recipient, $permissions) { $userFolder = $this->rootFolder->getUserFolder($initiator); $node = $userFolder->get($path); $share = $this->shareManager->newShare(); $share->setShareType($type)->setSharedWith($recipient)->setSharedBy($initiator)->setNode($node)->setPermissions($permissions); $share = $this->shareManager->createShare($share); return $share; }
/** * Get all mountpoints applicable for the user and check for shares where we need to update the etags * * @param \OCP\IUser $user * @param \OCP\Files\Storage\IStorageFactory $storageFactory * @return \OCP\Files\Mount\IMountPoint[] */ public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) { $shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1); $shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1)); // filter out excluded shares and group shares that includes self $shares = array_filter($shares, function (\OCP\Share\IShare $share) use($user) { return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID(); }); $mounts = []; foreach ($shares as $share) { try { $mounts[] = new SharedMount('\\OC\\Files\\Storage\\Shared', $mounts, ['user' => $user->getUID(), 'newShare' => $share], $storageFactory); } catch (\Exception $e) { $this->logger->logException($e); $this->logger->error('Error while trying to create shared mount'); } } // array_filter removes the null values from the array return array_filter($mounts); }
/** * Return a list of share types for outgoing shares * * @param \OCP\Files\Node $node file node * * @return int[] array of share types */ private function getShareTypes(\OCP\Files\Node $node) { $shareTypes = []; $requestedShareTypes = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE]; foreach ($requestedShareTypes as $requestedShareType) { // one of each type is enough to find out about the types $shares = $this->shareManager->getSharesBy($this->userId, $requestedShareType, $node, false, 1); if (!empty($shares)) { $shareTypes[] = $requestedShareType; } } return $shareTypes; }
public function testSharePasswordLinkInvalidSession() { $share = $this->getMock('OCP\\Share\\IShare'); $share->method('getPassword')->willReturn('password'); $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK); $share->method('getId')->willReturn('42'); $this->shareManager->expects($this->once())->method('getShareByToken')->willReturn($share); $this->shareManager->method('checkPassword')->with($this->equalTo($share), $this->equalTo('password'))->willReturn(false); $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); $this->session->method('get')->with('public_link_authenticated')->willReturn('43'); $result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); $this->assertFalse($result); }
/** * Validates a username and password * * This method should return true or false depending on if login * succeeded. * * @param string $username * @param string $password * * @return bool * @throws \Sabre\DAV\Exception\NotAuthenticated */ protected function validateUserPass($username, $password) { try { $share = $this->shareManager->getShareByToken($username); } catch (ShareNotFound $e) { return false; } $this->share = $share; \OC_User::setIncognitoMode(true); // check if the share is password protected if ($share->getPassword() !== null) { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { if ($this->shareManager->checkPassword($share, $password)) { return true; } else { if ($this->session->exists('public_link_authenticated') && $this->session->get('public_link_authenticated') === (string) $share->getId()) { return true; } else { if (in_array('XMLHttpRequest', explode(',', $this->request->getHeader('X-Requested-With')))) { // do not re-authenticate over ajax, use dummy auth name to prevent browser popup http_response_code(401); header('WWW-Authenticate', 'DummyBasic realm="' . $this->realm . '"'); throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls'); } return false; } } } else { if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) { return true; } else { return false; } } } else { return true; } }
/** * Since we have multiple providers but the OCS Share API v1 does * not support this we need to check all backends. * * @param string $id * @return \OCP\Share\IShare * @throws ShareNotFound */ private function getShareById($id) { $share = null; // First check if it is an internal share. try { $share = $this->shareManager->getShareById('ocinternal:' . $id); } catch (ShareNotFound $e) { if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) { throw new ShareNotFound(); } $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id); } return $share; }
/** * Validates the given password * * @fixme @LukasReschke says: Migrate old hashes to new hash format * Due to the fact that there is no reasonable functionality to update the password * of an existing share no migration is yet performed there. * The only possibility is to update the existing share which will result in a new * share ID and is a major hack. * * In the future the migration should be performed once there is a proper method * to update the share's password. (for example `$share->updatePassword($password)` * * @link https://github.com/owncloud/core/issues/10671 * * @param IShare $share * @param string $password * * @throws CheckException */ private function checkPassword($share, $password) { $newHash = ''; if ($this->shareManager->checkPassword($share, $password)) { // Save item id in session for future requests $this->session->set('public_link_authenticated', (string) $share->getId()); // @codeCoverageIgnoreStart if (!empty($newHash)) { // For future use } // @codeCoverageIgnoreEnd } else { throw new CheckException("Wrong password", Http::STATUS_UNAUTHORIZED); } }
public function testGetFilesByTagSingle() { $tagName = 'MyTagName'; $fileInfo = new FileInfo('/root.txt', $this->getMockBuilder('\\OC\\Files\\Storage\\Storage')->disableOriginalConstructor()->getMock(), '/var/www/root.txt', ['mtime' => 55, 'mimetype' => 'application/pdf', 'permissions' => 31, 'size' => 1234, 'etag' => 'MyEtag'], $this->getMockBuilder('\\OCP\\Files\\Mount\\IMountPoint')->disableOriginalConstructor()->getMock()); $node = $this->getMockBuilder('\\OC\\Files\\Node\\File')->disableOriginalConstructor()->getMock(); $node->expects($this->once())->method('getFileInfo')->will($this->returnValue($fileInfo)); $this->tagService->expects($this->once())->method('getFilesByTag')->with($this->equalTo([$tagName]))->will($this->returnValue([$node])); $this->shareManager->expects($this->any())->method('getSharesBy')->with($this->equalTo('user1'), $this->anything(), $node, $this->equalTo(false), $this->equalTo(1))->will($this->returnCallback(function ($userId, $shareType) { if ($shareType === \OCP\Share::SHARE_TYPE_USER || $shareType === \OCP\Share::SHARE_TYPE_LINK) { return ['dummy_share']; } return []; })); $expected = new DataResponse(['files' => [['id' => null, 'parentId' => null, 'mtime' => 55000, 'name' => 'root.txt', 'permissions' => 31, 'mimetype' => 'application/pdf', 'size' => 1234, 'type' => 'file', 'etag' => 'MyEtag', 'path' => '/', 'tags' => [['MyTagName']], 'shareTypes' => [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_LINK]]]]); $this->assertEquals($expected, $this->apiController->getFilesByTag([$tagName])); }
public function testGetSharedByWithLimit() { $node = $this->getMock('\\OCP\\Files\\File'); $node->method('getId')->willReturn(42); $node->method('getName')->willReturn('myFile'); $this->tokenHandler->method('generateToken')->willReturn('token'); $this->notifications->method('sendRemoteShare')->willReturn(true); $this->rootFolder->expects($this->never())->method($this->anything()); $share = $this->shareManager->newShare(); $share->setSharedWith('*****@*****.**')->setSharedBy('sharedBy')->setShareOwner('shareOwner')->setPermissions(19)->setNode($node); $this->provider->create($share); $share2 = $this->shareManager->newShare(); $share2->setSharedWith('*****@*****.**')->setSharedBy('sharedBy')->setShareOwner('shareOwner')->setPermissions(19)->setNode($node); $this->provider->create($share2); $shares = $this->provider->getSharesBy('shareOwner', \OCP\Share::SHARE_TYPE_REMOTE, null, true, 1, 1); $this->assertCount(1, $shares); $this->assertEquals('*****@*****.**', $shares[0]->getSharedWith()); }
/** * @param string $user * @return int */ public function getSharePermissions($user) { // check of we access a federated share if ($user !== null) { try { $share = $this->shareManager->getShareByToken($user); return $share->getPermissions(); } catch (ShareNotFound $e) { // ignore } } $storage = $this->info->getStorage(); $path = $this->info->getInternalPath(); if ($storage->instanceOfStorage('\\OC\\Files\\Storage\\Shared')) { /** @var \OC\Files\Storage\Shared $storage */ $permissions = (int) $storage->getShare()->getPermissions(); } else { $permissions = $storage->getPermissions($path); } /* * We can always share non moveable mount points with DELETE and UPDATE * Eventually we need to do this properly */ $mountpoint = $this->info->getMountPoint(); if (!$mountpoint instanceof MoveableMount) { $mountpointpath = $mountpoint->getMountPoint(); if (substr($mountpointpath, -1) === '/') { $mountpointpath = substr($mountpointpath, 0, -1); } if ($mountpointpath === $this->info->getPath()) { $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE; } } /* * Files can't have create or delete permissions */ if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) { $permissions &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE); } return $permissions; }
/** * @param OutputInterface $output */ private function restoreShares(OutputInterface $output) { $output->writeln("Restoring shares ..."); $progress = new ProgressBar($output, count($this->shares)); foreach ($this->shares as $share) { if ($share->getSharedWith() === $this->destinationUser) { $this->shareManager->deleteShare($share); } else { if ($share->getShareOwner() === $this->sourceUser) { $share->setShareOwner($this->destinationUser); } if ($share->getSharedBy() === $this->sourceUser) { $share->setSharedBy($this->destinationUser); } $this->shareManager->updateShare($share); } $progress->advance(); } $progress->finish(); $output->writeln(''); }
/** * @dataProvider sharesGetPropertiesDataProvider */ public function testPreloadThenGetProperties($shareTypes) { $sabreNode1 = $this->getMockBuilder('\\OCA\\DAV\\Connector\\Sabre\\File')->disableOriginalConstructor()->getMock(); $sabreNode1->expects($this->any())->method('getId')->will($this->returnValue(111)); $sabreNode1->expects($this->never())->method('getPath'); $sabreNode2 = $this->getMockBuilder('\\OCA\\DAV\\Connector\\Sabre\\File')->disableOriginalConstructor()->getMock(); $sabreNode2->expects($this->any())->method('getId')->will($this->returnValue(222)); $sabreNode2->expects($this->never())->method('getPath'); $sabreNode = $this->getMockBuilder('\\OCA\\DAV\\Connector\\Sabre\\Directory')->disableOriginalConstructor()->getMock(); $sabreNode->expects($this->any())->method('getId')->will($this->returnValue(123)); // never, because we use getDirectoryListing from the Node API instead $sabreNode->expects($this->never())->method('getChildren'); $sabreNode->expects($this->any())->method('getPath')->will($this->returnValue('/subdir')); // node API nodes $node = $this->getMock('\\OCP\\Files\\Folder'); $node->expects($this->any())->method('getId')->will($this->returnValue(123)); $node1 = $this->getMock('\\OCP\\Files\\File'); $node1->expects($this->any())->method('getId')->will($this->returnValue(111)); $node2 = $this->getMock('\\OCP\\Files\\File'); $node2->expects($this->any())->method('getId')->will($this->returnValue(222)); $node->expects($this->once())->method('getDirectoryListing')->will($this->returnValue([$node1, $node2])); $this->userFolder->expects($this->once())->method('get')->with('/subdir')->will($this->returnValue($node)); $this->shareManager->expects($this->any())->method('getSharesBy')->with($this->equalTo('user1'), $this->anything(), $this->anything(), $this->equalTo(false), $this->equalTo(1))->will($this->returnCallback(function ($userId, $requestedShareType, $node, $flag, $limit) use($shareTypes) { if ($node->getId() === 111 && in_array($requestedShareType, $shareTypes)) { return ['dummyshare']; } return []; })); // simulate sabre recursive PROPFIND traversal $propFindRoot = new \Sabre\DAV\PropFind('/subdir', [self::SHARETYPES_PROPERTYNAME], 1); $propFind1 = new \Sabre\DAV\PropFind('/subdir/test.txt', [self::SHARETYPES_PROPERTYNAME], 0); $propFind2 = new \Sabre\DAV\PropFind('/subdir/test2.txt', [self::SHARETYPES_PROPERTYNAME], 0); $this->plugin->handleGetProperties($propFindRoot, $sabreNode); $this->plugin->handleGetProperties($propFind1, $sabreNode1); $this->plugin->handleGetProperties($propFind2, $sabreNode2); $result = $propFind1->getResultForMultiStatus(); $this->assertEmpty($result[404]); unset($result[404]); $this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes()); }
/** * Build super shares (virtual share) by grouping them by node id and target, * then for each group compute the super share and return it along with the matching * grouped shares. The most permissive permissions are used based on the permissions * of all shares within the group. * * @param \OCP\Share\IShare[] $allShares * @return array Tuple of [superShare, groupedShares] */ private function buildSuperShares(array $allShares) { $result = []; $groupedShares = $this->groupShares($allShares); /** @var \OCP\Share\IShare[] $shares */ foreach ($groupedShares as $shares) { if (count($shares) === 0) { continue; } $superShare = $this->shareManager->newShare(); // compute super share based on first entry of the group $superShare->setId($shares[0]->getId())->setShareOwner($shares[0]->getShareOwner())->setNodeId($shares[0]->getNodeId())->setTarget($shares[0]->getTarget()); // use most permissive permissions $permissions = 0; foreach ($shares as $share) { $permissions |= $share->getPermissions(); } $superShare->setPermissions($permissions); $result[] = [$superShare, $shares]; } return $result; }
/** * @dataProvider dataSearch * * @param array $getData * @param string $apiSetting * @param string $enumSetting * @param bool $remoteSharingEnabled * @param string $search * @param string $itemType * @param array $shareTypes * @param int $page * @param int $perPage * @param bool $shareWithGroupOnly * @param bool $shareeEnumeration * @param bool $allowGroupSharing */ public function testSearch($getData, $apiSetting, $enumSetting, $remoteSharingEnabled, $search, $itemType, $shareTypes, $page, $perPage, $shareWithGroupOnly, $shareeEnumeration, $allowGroupSharing) { $oldGet = $_GET; $_GET = $getData; $config = $this->getMockBuilder('OCP\\IConfig')->disableOriginalConstructor()->getMock(); $config->expects($this->exactly(2))->method('getAppValue')->with('core', $this->anything(), $this->anything())->willReturnMap([['core', 'shareapi_only_share_with_group_members', 'no', $apiSetting], ['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', $enumSetting]]); $this->shareManager->expects($this->once())->method('allowGroupSharing')->willReturn($allowGroupSharing); $sharees = $this->getMockBuilder('\\OCA\\Files_Sharing\\API\\Sharees')->setConstructorArgs([$this->groupManager, $this->userManager, $this->contactsManager, $config, $this->session, $this->getMockBuilder('OCP\\IURLGenerator')->disableOriginalConstructor()->getMock(), $this->getMockBuilder('OCP\\IRequest')->disableOriginalConstructor()->getMock(), $this->getMockBuilder('OCP\\ILogger')->disableOriginalConstructor()->getMock(), $this->shareManager])->setMethods(array('searchSharees', 'isRemoteSharingAllowed'))->getMock(); $sharees->expects($this->once())->method('searchSharees')->with($search, $itemType, $shareTypes, $page, $perPage)->willReturnCallback(function ($isearch, $iitemType, $ishareTypes, $ipage, $iperPage) use($search, $itemType, $shareTypes, $page, $perPage) { // We are doing strict comparisons here, so we can differ 0/'' and null on shareType/itemType $this->assertSame($search, $isearch); $this->assertSame($itemType, $iitemType); $this->assertSame($shareTypes, $ishareTypes); $this->assertSame($page, $ipage); $this->assertSame($perPage, $iperPage); return new \OC_OCS_Result([]); }); $sharees->expects($this->any())->method('isRemoteSharingAllowed')->with($itemType)->willReturn($remoteSharingEnabled); /** @var \PHPUnit_Framework_MockObject_MockObject|\OCA\Files_Sharing\API\Sharees $sharees */ $this->assertInstanceOf('\\OC_OCS_Result', $sharees->search()); $this->assertSame($shareWithGroupOnly, $this->invokePrivate($sharees, 'shareWithGroupOnly')); $this->assertSame($shareeEnumeration, $this->invokePrivate($sharees, 'shareeEnumeration')); $_GET = $oldGet; }
/** * @return \OC_OCS_Result */ public function search() { $search = isset($_GET['search']) ? (string) $_GET['search'] : ''; $itemType = isset($_GET['itemType']) ? (string) $_GET['itemType'] : null; $page = isset($_GET['page']) ? (int) $_GET['page'] : 1; $perPage = isset($_GET['perPage']) ? (int) $_GET['perPage'] : 200; if ($perPage <= 0) { return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST, 'Invalid perPage argument'); } if ($page <= 0) { return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST, 'Invalid page'); } $shareTypes = [Share::SHARE_TYPE_USER]; if ($this->shareManager->allowGroupSharing()) { $shareTypes[] = Share::SHARE_TYPE_GROUP; } $shareTypes[] = Share::SHARE_TYPE_REMOTE; if (isset($_GET['shareType']) && is_array($_GET['shareType'])) { $shareTypes = array_intersect($shareTypes, $_GET['shareType']); sort($shareTypes); } else { if (isset($_GET['shareType']) && is_numeric($_GET['shareType'])) { $shareTypes = array_intersect($shareTypes, [(int) $_GET['shareType']]); sort($shareTypes); } } if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes) && !$this->isRemoteSharingAllowed($itemType)) { // Remove remote shares from type array, because it is not allowed. $shareTypes = array_diff($shareTypes, [Share::SHARE_TYPE_REMOTE]); } $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes'; $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; $this->limit = (int) $perPage; $this->offset = $perPage * ($page - 1); return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage); }
public function testGetPathByIdShareSubFolder() { self::loginHelper(self::TEST_FILES_SHARING_API_USER1); \OC\Files\Filesystem::mkdir('foo'); \OC\Files\Filesystem::mkdir('foo/bar'); \OC\Files\Filesystem::touch('foo/bar/test.txt'); $folderInfo = \OC\Files\Filesystem::getFileInfo('foo'); $fileInfo = \OC\Files\Filesystem::getFileInfo('foo/bar/test.txt'); $rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1); $node = $rootFolder->get('foo'); $share = $this->shareManager->newShare(); $share->setNode($node)->setShareType(\OCP\Share::SHARE_TYPE_USER)->setSharedWith(self::TEST_FILES_SHARING_API_USER2)->setSharedBy(self::TEST_FILES_SHARING_API_USER1)->setPermissions(\OCP\Constants::PERMISSION_ALL); $this->shareManager->createShare($share); \OC_Util::tearDownFS(); self::loginHelper(self::TEST_FILES_SHARING_API_USER2); $this->assertTrue(\OC\Files\Filesystem::file_exists('/foo')); list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/foo'); /** * @var \OC\Files\Storage\Shared $sharedStorage */ $sharedCache = $sharedStorage->getCache(); $this->assertEquals('', $sharedCache->getPathById($folderInfo->getId())); $this->assertEquals('bar/test.txt', $sharedCache->getPathById($fileInfo->getId())); }
/** * @PublicPage * @NoCSRFRequired * * @param string $token * @param string $files * @param string $path * @param string $downloadStartSecret * @return void|RedirectResponse */ public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') { \OC_User::setIncognitoMode(true); $share = $this->shareManager->getShareByToken($token); // Share is password protected - check whether the user is permitted to access the share if ($share->getPassword() !== null && !$this->linkShareAuth($share)) { return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate', ['token' => $token])); } $files_list = null; if (!is_null($files)) { // download selected files $files_list = json_decode($files); // in case we get only a single file if ($files_list === null) { $files_list = [$files]; } } $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath()); if (!$this->validateShare($share)) { throw new NotFoundException(); } // Single file share if ($share->getNode() instanceof \OCP\Files\File) { // Single file download $event = $this->activityManager->generateEvent(); $event->setApp('files_sharing')->setType(Activity::TYPE_PUBLIC_LINKS)->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($share->getNode()->getPath())])->setAffectedUser($share->getShareOwner())->setObject('files', $share->getNode()->getId(), $userFolder->getRelativePath($share->getNode()->getPath())); $this->activityManager->publish($event); } else { /** @var \OCP\Files\Folder $node */ $node = $share->getNode(); // Try to get the path if ($path !== '') { try { $node = $node->get($path); } catch (NotFoundException $e) { $this->emitAccessShareHook($share, 404, 'Share not found'); return new NotFoundResponse(); } } $originalSharePath = $userFolder->getRelativePath($node->getPath()); if ($node instanceof \OCP\Files\File) { // Single file download $event = $this->activityManager->generateEvent(); $event->setApp('files_sharing')->setType(Activity::TYPE_PUBLIC_LINKS)->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($node->getPath())])->setAffectedUser($share->getShareOwner())->setObject('files', $node->getId(), $userFolder->getRelativePath($node->getPath())); $this->activityManager->publish($event); } else { if (!empty($files_list)) { /** @var \OCP\Files\Folder $node */ // Subset of files is downloaded foreach ($files_list as $file) { $subNode = $node->get($file); $event = $this->activityManager->generateEvent(); $event->setApp('files_sharing')->setType(Activity::TYPE_PUBLIC_LINKS)->setAffectedUser($share->getShareOwner())->setObject('files', $subNode->getId(), $userFolder->getRelativePath($subNode->getPath())); if ($subNode instanceof \OCP\Files\File) { $event->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($subNode->getPath())]); } else { $event->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED, [$userFolder->getRelativePath($subNode->getPath())]); } $this->activityManager->publish($event); } } else { // The folder is downloaded $event = $this->activityManager->generateEvent(); $event->setApp('files_sharing')->setType(Activity::TYPE_PUBLIC_LINKS)->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED, [$userFolder->getRelativePath($node->getPath())])->setAffectedUser($share->getShareOwner())->setObject('files', $node->getId(), $userFolder->getRelativePath($node->getPath())); $this->activityManager->publish($event); } } } /* FIXME: We should do this all nicely in OCP */ OC_Util::tearDownFS(); OC_Util::setupFS($share->getShareOwner()); /** * this sets a cookie to be able to recognize the start of the download * the content must not be longer than 32 characters and must only contain * alphanumeric characters */ if (!empty($downloadStartSecret) && !isset($downloadStartSecret[32]) && preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) { // FIXME: set on the response once we use an actual app framework response setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/'); } $this->emitAccessShareHook($share); $server_params = array('head' => $this->request->getMethod() == 'HEAD'); /** * Http range requests support */ if (isset($_SERVER['HTTP_RANGE'])) { $server_params['range'] = $this->request->getHeader('Range'); } // download selected files if (!is_null($files) && $files !== '') { // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well // after dispatching the request which results in a "Cannot modify header information" notice. OC_Files::get($originalSharePath, $files_list, $server_params); exit; } else { // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well // after dispatching the request which results in a "Cannot modify header information" notice. OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params); exit; } }
/** * @param int $id * @return \OC_OCS_Result */ public function updateShare($id) { // Try both our default and our federated provider $share = null; try { $share = $this->shareManager->getShareById('ocinternal:' . $id); } catch (ShareNotFound $e) { //Ignore for now //return new \OC_OCS_Result(null, 404, 'wrong share ID, share doesn\'t exist.'); } // Could not find the share as internal share... maybe it is a federated share if ($share === null) { return \OCA\Files_Sharing\API\Local::updateShare(['id' => $id]); } if (!$this->canAccessShare($share)) { return new \OC_OCS_Result(null, 404, 'wrong share Id, share doesn\'t exist.'); } $permissions = $this->request->getParam('permissions', null); $password = $this->request->getParam('password', null); $publicUpload = $this->request->getParam('publicUpload', null); $expireDate = $this->request->getParam('expireDate', null); /* * expirationdate, password and publicUpload only make sense for link shares */ if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) { if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null) { return new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given'); } $newPermissions = null; if ($publicUpload === 'true') { $newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE; } else { if ($publicUpload === 'false') { $newPermissions = \OCP\Constants::PERMISSION_READ; } } if ($permissions !== null) { $newPermissions = (int) $permissions; } if ($newPermissions !== null && $newPermissions !== \OCP\Constants::PERMISSION_READ && $newPermissions !== (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE)) { return new \OC_OCS_Result(null, 400, 'can\'t change permission for public link share'); } if ($newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE)) { if (!$this->shareManager->shareApiLinkAllowPublicUpload()) { return new \OC_OCS_Result(null, 403, 'public upload disabled by the administrator'); } if (!$share->getNode() instanceof \OCP\Files\Folder) { return new \OC_OCS_Result(null, 400, "public upload is only possible for public shared folders"); } } if ($newPermissions !== null) { $share->setPermissions($newPermissions); } if ($expireDate === '') { $share->setExpirationDate(null); } else { if ($expireDate !== null) { try { $expireDate = $this->parseDate($expireDate); } catch (\Exception $e) { return new \OC_OCS_Result(null, 400, $e->getMessage()); } $share->setExpirationDate($expireDate); } } if ($password === '') { $share->setPassword(null); } else { if ($password !== null) { $share->setPassword($password); } } } else { // For other shares only permissions is valid. if ($permissions === null) { return new \OC_OCS_Result(null, 400, 'Wrong or no update parameter given'); } else { $permissions = (int) $permissions; $share->setPermissions($permissions); } } try { $share = $this->shareManager->updateShare($share); } catch (\Exception $e) { return new \OC_OCS_Result(null, 400, $e->getMessage()); } return new \OC_OCS_Result($this->formatShare($share)); }