diff --git a/apps/files_sharing/lib/controllers/sharecontroller.php b/apps/files_sharing/lib/controllers/sharecontroller.php index bbe68096b5..dae61a3537 100644 --- a/apps/files_sharing/lib/controllers/sharecontroller.php +++ b/apps/files_sharing/lib/controllers/sharecontroller.php @@ -30,7 +30,6 @@ namespace OCA\Files_Sharing\Controllers; use OC; -use OC\Files\Filesystem; use OC_Files; use OC_Util; use OCP; @@ -71,7 +70,7 @@ class ShareController extends Controller { protected $logger; /** @var OCP\Activity\IManager */ protected $activityManager; - /** @var OC\Share20\Manager */ + /** @var OCP\Share\IManager */ protected $shareManager; /** @var ISession */ protected $session; @@ -88,7 +87,7 @@ class ShareController extends Controller { * @param IUserManager $userManager * @param ILogger $logger * @param OCP\Activity\IManager $activityManager - * @param \OC\Share20\Manager $shareManager + * @param \OCP\Share\IManager $shareManager * @param ISession $session * @param IPreview $previewManager * @param IRootFolder $rootFolder @@ -100,7 +99,7 @@ class ShareController extends Controller { IUserManager $userManager, ILogger $logger, \OCP\Activity\IManager $activityManager, - \OC\Share20\Manager $shareManager, + \OCP\Share\IManager $shareManager, ISession $session, IPreview $previewManager, IRootFolder $rootFolder) { @@ -177,6 +176,7 @@ class ShareController extends Controller { if ($this->shareManager->checkPassword($share, $password)) { $this->session->set('public_link_authenticated', (string)$share->getId()); } else { + $this->emitAccessShareHook($share, 403, 'Wrong password'); return false; } } else { @@ -189,6 +189,44 @@ class ShareController extends Controller { return true; } + /** + * throws hooks when a share is attempted to be accessed + * + * @param \OCP\Share\IShare|string $share the Share instance if available, + * otherwise token + * @param int $errorCode + * @param string $errorMessage + * @throws OC\HintException + * @throws OC\ServerNotAvailableException + */ + protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') { + $itemType = $itemSource = $uidOwner = ''; + $token = $share; + $exception = null; + if($share instanceof \OCP\Share\IShare) { + try { + $token = $share->getToken(); + $uidOwner = $share->getSharedBy(); + $itemType = $share->getNodeType(); + $itemSource = $share->getNodeId(); + } catch (\Exception $e) { + // we log what we know and pass on the exception afterwards + $exception = $e; + } + } + \OC_Hook::emit('OCP\Share', 'share_link_access', [ + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'uidOwner' => $uidOwner, + 'token' => $token, + 'errorCode' => $errorCode, + 'errorMessage' => $errorMessage, + ]); + if(!is_null($exception)) { + throw $exception; + } + } + /** * @PublicPage * @NoCSRFRequired @@ -205,6 +243,7 @@ class ShareController extends Controller { try { $share = $this->shareManager->getShareByToken($token); } catch (ShareNotFound $e) { + $this->emitAccessShareHook($token, 404, 'Share not found'); return new NotFoundResponse(); } @@ -215,8 +254,14 @@ class ShareController extends Controller { } // We can't get the path of a file share - if ($share->getNode() instanceof \OCP\Files\File && $path !== '') { - throw new NotFoundException(); + try { + if ($share->getNode() instanceof \OCP\Files\File && $path !== '') { + $this->emitAccessShareHook($share, 404, 'Share not found'); + throw new NotFoundException(); + } + } catch (\Exception $e) { + $this->emitAccessShareHook($share, 404, 'Share not found'); + throw $e; } $rootFolder = null; @@ -227,6 +272,7 @@ class ShareController extends Controller { try { $path = $rootFolder->get($path); } catch (\OCP\Files\NotFoundException $e) { + $this->emitAccessShareHook($share, 404, 'Share not found'); throw new NotFoundException(); } } @@ -287,6 +333,8 @@ class ShareController extends Controller { $response = new TemplateResponse($this->appName, 'public', $shareTmpl, 'base'); $response->setContentSecurityPolicy($csp); + $this->emitAccessShareHook($share); + return $response; } @@ -344,6 +392,7 @@ class ShareController extends Controller { try { $node = $node->get($path); } catch (NotFoundException $e) { + $this->emitAccessShareHook($share, 404, 'Share not found'); return new NotFoundResponse(); } } @@ -409,6 +458,8 @@ class ShareController extends Controller { setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/'); } + $this->emitAccessShareHook($share); + // download selected files if (!is_null($files)) { // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well diff --git a/apps/files_sharing/tests/controller/sharecontroller.php b/apps/files_sharing/tests/controller/sharecontroller.php index 22e15972cd..11dc082390 100644 --- a/apps/files_sharing/tests/controller/sharecontroller.php +++ b/apps/files_sharing/tests/controller/sharecontroller.php @@ -219,7 +219,11 @@ class ShareControllerTest extends \Test\TestCase { public function testAuthenticateInvalidPassword() { $share = \OC::$server->getShareManager()->newShare(); - $share->setId(42); + $share->setNodeId(100) + ->setNodeType('file') + ->setToken('token') + ->setSharedBy('initiator') + ->setId(42); $this->shareManager ->expects($this->once()) @@ -237,6 +241,20 @@ class ShareControllerTest extends \Test\TestCase { ->expects($this->never()) ->method('set'); + $hookListner = $this->getMockBuilder('Dummy')->setMethods(['access'])->getMock(); + \OCP\Util::connectHook('OCP\Share', 'share_link_access', $hookListner, 'access'); + + $hookListner->expects($this->once()) + ->method('access') + ->with($this->callback(function(array $data) { + return $data['itemType'] === 'file' && + $data['itemSource'] === 100 && + $data['uidOwner'] === 'initiator' && + $data['token'] === 'token' && + $data['errorCode'] === 403 && + $data['errorMessage'] === 'Wrong password'; + })); + $response = $this->shareController->authenticate('token', 'invalidpassword'); $expectedResponse = new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest'); $this->assertEquals($expectedResponse, $response); diff --git a/lib/private/share20/manager.php b/lib/private/share20/manager.php index 7cd44a7cb3..3a19bd2dc3 100644 --- a/lib/private/share20/manager.php +++ b/lib/private/share20/manager.php @@ -597,7 +597,7 @@ class Manager implements IManager { } } - if ($share->getExpirationDate() !== $originalShare->getExpirationDate()) { + if ($share->getExpirationDate() != $originalShare->getExpirationDate()) { //Verify the expiration date $this->validateExpirationDate($share); $expirationDateUpdated = true; @@ -619,6 +619,16 @@ class Manager implements IManager { ]); } + if ($share->getPassword() !== $originalShare->getPassword()) { + \OC_Hook::emit('OCP\Share', 'post_update_password', [ + 'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder', + 'itemSource' => $share->getNode()->getId(), + 'uidOwner' => $share->getSharedBy(), + 'token' => $share->getToken(), + 'disabled' => is_null($share->getPassword()), + ]); + } + if ($share->getPermissions() !== $originalShare->getPermissions()) { $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); \OC_Hook::emit('OCP\Share', 'post_update_permissions', array( diff --git a/lib/private/share20/share.php b/lib/private/share20/share.php index cd30f24c42..e84d52b63a 100644 --- a/lib/private/share20/share.php +++ b/lib/private/share20/share.php @@ -163,6 +163,7 @@ class Share implements \OCP\Share\IShare { } $this->nodeType = $type; + return $this; } /**