diff --git a/apps/files_sharing/api/ocssharewrapper.php b/apps/files_sharing/api/ocssharewrapper.php index ca04c656c2..2896f3fbf0 100644 --- a/apps/files_sharing/api/ocssharewrapper.php +++ b/apps/files_sharing/api/ocssharewrapper.php @@ -29,13 +29,17 @@ class OCSShareWrapper { return new Share20OCS( new \OC\Share20\Manager( \OC::$server->getLogger(), - \OC::$server->getAppConfig(), + \OC::$server->getConfig(), new \OC\Share20\DefaultShareProvider( \OC::$server->getDatabaseConnection(), \OC::$server->getUserManager(), \OC::$server->getGroupManager(), \OC::$server->getRootFolder() - ) + ), + \OC::$server->getSecureRandom(), + \OC::$server->getHasher(), + \OC::$server->getMountManager(), + \OC::$server->getGroupManager() ), \OC::$server->getGroupManager(), \OC::$server->getUserManager(), @@ -49,8 +53,8 @@ class OCSShareWrapper { return \OCA\Files_Sharing\API\Local::getAllShares($params); } - public function createShare($params) { - return \OCA\Files_Sharing\API\Local::createShare($params); + public function createShare() { + return $this->getShare20OCS()->createShare(); } public function getShare($params) { diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php index 6c25b4a442..bf644ce00f 100644 --- a/apps/files_sharing/api/share20ocs.php +++ b/apps/files_sharing/api/share20ocs.php @@ -25,7 +25,6 @@ use OC\Share20\IShare; use OCP\IGroupManager; use OCP\IUserManager; use OCP\IRequest; -use OCP\Files\Folder; use OCP\IURLGenerator; use OCP\IUser; use OCP\Files\IRootFolder; @@ -191,6 +190,127 @@ class Share20OCS { return new \OC_OCS_Result(); } + /** + * @return \OC_OCS_Result + */ + public function createShare() { + $share = $this->shareManager->newShare(); + + // Verify path + $path = $this->request->getParam('path', null); + if ($path === null) { + return new \OC_OCS_Result(null, 404, 'please specify a file or folder path'); + } + + $userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID()); + try { + $path = $userFolder->get($path); + } catch (\OCP\Files\NotFoundException $e) { + return new \OC_OCS_Result(null, 404, 'wrong path, file/folder doesn\'t exist'); + } + + $share->setPath($path); + + // Parse permissions (if available) + $permissions = $this->request->getParam('permissions', null); + if ($permissions === null) { + $permissions = \OCP\Constants::PERMISSION_ALL; + } else { + $permissions = (int)$permissions; + } + + if ($permissions < 0 || $permissions > \OCP\Constants::PERMISSION_ALL) { + return new \OC_OCS_Result(null, 404, 'invalid permissions'); + } + + // Shares always require read permissions + $permissions |= \OCP\Constants::PERMISSION_READ; + + if ($path instanceof \OCP\Files\File) { + // Single file shares should never have delete or create permissions + $permissions &= ~\OCP\Constants::PERMISSION_DELETE; + $permissions &= ~\OCP\Constants::PERMISSION_CREATE; + } + + $shareWith = $this->request->getParam('shareWith', null); + $shareType = (int)$this->request->getParam('shareType', '-1'); + + if ($shareType === \OCP\Share::SHARE_TYPE_USER) { + // Valid user is required to share + if ($shareWith === null || !$this->userManager->userExists($shareWith)) { + return new \OC_OCS_Result(null, 404, 'please specify a valid user'); + } + $share->setSharedWith($this->userManager->get($shareWith)); + $share->setPermissions($permissions); + } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) { + // Valid group is required to share + if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) { + return new \OC_OCS_Result(null, 404, 'please specify a valid group'); + } + $share->setSharedWith($this->groupManager->get($shareWith)); + $share->setPermissions($permissions); + } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) { + //Can we even share links? + if (!$this->shareManager->shareApiAllowLinks()) { + return new \OC_OCS_Result(null, 404, 'public link sharing is disabled by the administrator'); + } + + $publicUpload = $this->request->getParam('publicUpload', null); + if ($publicUpload === 'true') { + // Check if public upload is allowed + if (!$this->shareManager->shareApiLinkAllowPublicUpload()) { + return new \OC_OCS_Result(null, 403, '"public upload disabled by the administrator'); + } + + // Public upload can only be set for folders + if ($path instanceof \OCP\Files\File) { + return new \OC_OCS_Result(null, 404, '"public upload is only possible for public shared folders'); + } + + $share->setPermissions( + \OCP\Constants::PERMISSION_READ | + \OCP\Constants::PERMISSION_CREATE | + \OCP\Constants::PERMISSION_UPDATE + ); + } else { + $share->setPermissions(\OCP\Constants::PERMISSION_READ); + } + + // Set password + $share->setPassword($this->request->getParam('password', null)); + + //Expire date + $expireDate = $this->request->getParam('expireDate', null); + + if ($expireDate !== null) { + try { + $expireDate = $this->parseDate($expireDate); + $share->setExpirationDate($expireDate); + } catch (\Exception $e) { + return new \OC_OCS_Result(null, 404, 'Invalid Date. Format must be YYYY-MM-DD.'); + } + } + + } else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) { + //fixme Remote shares are handled by old code path for now + return \OCA\Files_Sharing\API\Local::createShare([]); + } else { + return new \OC_OCS_Result(null, 400, "unknown share type"); + } + + $share->setShareType($shareType); + $share->setSharedBy($this->currentUser); + + try { + $share = $this->shareManager->createShare($share); + } catch (\Exception $e) { + return new \OC_OCS_Result(null, 404, $e->getMessage()); + } + + $share = $this->formatShare($share); + return new \OC_OCS_Result($share); + } + /** * @param IShare $share * @return bool @@ -216,4 +336,30 @@ class Share20OCS { return false; } + + /** + * Make sure that the passed date is valid ISO 8601 + * So YYYY-MM-DD + * If not throw an exception + * + * @param string $expireDate + * + * @throws \Exception + * @return \DateTime + */ + private function parseDate($expireDate) { + try { + $date = new \DateTime($expireDate); + } catch (\Exception $e) { + throw new \Exception('Invalid date. Format must be YYYY-MM-DD'); + } + + if ($date === false) { + throw new \Exception('Invalid date. Format must be YYYY-MM-DD'); + } + + $date->setTime(0,0,0); + + return $date; + } } diff --git a/apps/files_sharing/tests/api/share20ocstest.php b/apps/files_sharing/tests/api/share20ocstest.php index b7c56fe17f..2d69636541 100644 --- a/apps/files_sharing/tests/api/share20ocstest.php +++ b/apps/files_sharing/tests/api/share20ocstest.php @@ -65,6 +65,7 @@ class Share20OCSTest extends \Test\TestCase { $this->rootFolder = $this->getMock('OCP\Files\IRootFolder'); $this->urlGenerator = $this->getMock('OCP\IURLGenerator'); $this->currentUser = $this->getMock('OCP\IUser'); + $this->currentUser->method('getUID')->willReturn('currentUser'); $this->ocs = new Share20OCS( $this->shareManager, @@ -391,4 +392,280 @@ class Share20OCSTest extends \Test\TestCase { $share->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK); $this->assertFalse($this->invokePrivate($this->ocs, 'canAccessShare', [$share])); } + + public function testCreateShareNoPath() { + $expected = new \OC_OCS_Result(null, 404, 'please specify a file or folder path'); + + $result = $this->ocs->createShare(); + + $this->assertEquals($expected->getMeta(), $result->getMeta()); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareInvalidPath() { + $this->request + ->method('getParam') + ->will($this->returnValueMap([ + ['path', null, 'invalid-path'], + ])); + + $userFolder = $this->getMock('\OCP\Files\Folder'); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $userFolder->expects($this->once()) + ->method('get') + ->with('invalid-path') + ->will($this->throwException(new \OCP\Files\NotFoundException())); + + $expected = new \OC_OCS_Result(null, 404, 'wrong path, file/folder doesn\'t exist'); + + $result = $this->ocs->createShare(); + + $this->assertEquals($expected->getMeta(), $result->getMeta()); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareInvalidPermissions() { + $share = $this->getMock('\OC\Share20\IShare'); + $this->shareManager->method('newShare')->willReturn($share); + + $this->request + ->method('getParam') + ->will($this->returnValueMap([ + ['path', null, 'valid-path'], + ['permissions', null, 32], + ])); + + $userFolder = $this->getMock('\OCP\Files\Folder'); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $path = $this->getMock('\OCP\Files\File'); + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + + $expected = new \OC_OCS_Result(null, 404, 'invalid permissions'); + + $result = $this->ocs->createShare(); + + $this->assertEquals($expected->getMeta(), $result->getMeta()); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareUserNoShareWith() { + $share = $this->getMock('\OC\Share20\IShare'); + $this->shareManager->method('newShare')->willReturn($share); + + $this->request + ->method('getParam') + ->will($this->returnValueMap([ + ['path', null, 'valid-path'], + ['permissions', null, \OCP\Constants::PERMISSION_ALL], + ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER], + ])); + + $userFolder = $this->getMock('\OCP\Files\Folder'); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $path = $this->getMock('\OCP\Files\File'); + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + + $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user'); + + $result = $this->ocs->createShare(); + + $this->assertEquals($expected->getMeta(), $result->getMeta()); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareUserNoValidShareWith() { + $share = $this->getMock('\OC\Share20\IShare'); + $this->shareManager->method('newShare')->willReturn($share); + + $this->request + ->method('getParam') + ->will($this->returnValueMap([ + ['path', null, 'valid-path'], + ['permissions', null, \OCP\Constants::PERMISSION_ALL], + ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER], + ['shareWith', $this->any(), 'invalidUser'], + ])); + + $userFolder = $this->getMock('\OCP\Files\Folder'); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $path = $this->getMock('\OCP\Files\File'); + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + + $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user'); + + $result = $this->ocs->createShare(); + + $this->assertEquals($expected->getMeta(), $result->getMeta()); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareUser() { + $share = $this->getMock('\OC\Share20\IShare'); + $this->shareManager->method('newShare')->willReturn($share); + + $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS') + ->setConstructorArgs([ + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->request, + $this->rootFolder, + $this->urlGenerator, + $this->currentUser + ])->setMethods(['formatShare']) + ->getMock(); + + $this->request + ->method('getParam') + ->will($this->returnValueMap([ + ['path', null, 'valid-path'], + ['permissions', null, \OCP\Constants::PERMISSION_ALL], + ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_USER], + ['shareWith', null, 'validUser'], + ])); + + $userFolder = $this->getMock('\OCP\Files\Folder'); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $path = $this->getMock('\OCP\Files\File'); + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + + $user = $this->getMock('\OCP\IUser'); + $this->userManager->method('userExists')->with('validUser')->willReturn(true); + $this->userManager->method('get')->with('validUser')->willReturn($user); + + $share->method('setPath')->with($path); + $share->method('setPermissions') + ->with( + \OCP\Constants::PERMISSION_ALL & + ~\OCP\Constants::PERMISSION_DELETE & + ~\OCP\Constants::PERMISSION_CREATE); + $share->method('setShareType')->with(\OCP\Share::SHARE_TYPE_USER); + $share->method('setSharedWith')->with($user); + $share->method('setSharedBy')->with($this->currentUser); + + $expected = new \OC_OCS_Result(); + $result = $ocs->createShare(); + + $this->assertEquals($expected->getMeta(), $result->getMeta()); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareGroupNoValidShareWith() { + $share = $this->getMock('\OC\Share20\IShare'); + $this->shareManager->method('newShare')->willReturn($share); + + $this->request + ->method('getParam') + ->will($this->returnValueMap([ + ['path', null, 'valid-path'], + ['permissions', null, \OCP\Constants::PERMISSION_ALL], + ['shareType', $this->any(), \OCP\Share::SHARE_TYPE_GROUP], + ['shareWith', $this->any(), 'invalidGroup'], + ])); + + $userFolder = $this->getMock('\OCP\Files\Folder'); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $path = $this->getMock('\OCP\Files\File'); + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + + $expected = new \OC_OCS_Result(null, 404, 'please specify a valid user'); + + $result = $this->ocs->createShare(); + + $this->assertEquals($expected->getMeta(), $result->getMeta()); + $this->assertEquals($expected->getData(), $result->getData()); + } + + public function testCreateShareGroup() { + $share = $this->getMock('\OC\Share20\IShare'); + $this->shareManager->method('newShare')->willReturn($share); + + $ocs = $this->getMockBuilder('OCA\Files_Sharing\API\Share20OCS') + ->setConstructorArgs([ + $this->shareManager, + $this->groupManager, + $this->userManager, + $this->request, + $this->rootFolder, + $this->urlGenerator, + $this->currentUser + ])->setMethods(['formatShare']) + ->getMock(); + + $this->request + ->method('getParam') + ->will($this->returnValueMap([ + ['path', null, 'valid-path'], + ['permissions', null, \OCP\Constants::PERMISSION_ALL], + ['shareType', '-1', \OCP\Share::SHARE_TYPE_GROUP], + ['shareWith', null, 'validGroup'], + ])); + + $userFolder = $this->getMock('\OCP\Files\Folder'); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('currentUser') + ->willReturn($userFolder); + + $path = $this->getMock('\OCP\Files\Folder'); + $userFolder->expects($this->once()) + ->method('get') + ->with('valid-path') + ->willReturn($path); + + $group = $this->getMock('\OCP\IGroup'); + $this->groupManager->method('groupExists')->with('validGroup')->willReturn(true); + $this->groupManager->method('get')->with('validGroup')->willReturn($group); + + $share->method('setPath')->with($path); + $share->method('setPermissions')->with(\OCP\Constants::PERMISSION_ALL); + $share->method('setShareType')->with(\OCP\Share::SHARE_TYPE_GROUP); + $share->method('setSharedWith')->with($group); + $share->method('setSharedBy')->with($this->currentUser); + + $expected = new \OC_OCS_Result(); + $result = $ocs->createShare(); + + $this->assertEquals($expected->getMeta(), $result->getMeta()); + $this->assertEquals($expected->getData(), $result->getData()); + } }