/** * Validates a token to make sure its linked to a valid resource * * Uses Share 2.0 * * @fixme setIncognitoMode in 8.1 https://github.com/owncloud/core/pull/12912 * * @param string $token * * @throws CheckException * @return IShare */ private function getShare($token) { // Allows a logged in user to access public links \OC_User::setIncognitoMode(true); try { $share = $this->shareManager->getShareByToken($token); } catch (ShareNotFound $e) { throw new CheckException($e->getMessage(), Http::STATUS_NOT_FOUND); } $this->checkShareIsValid($share, $token); $this->checkItemType($share); return $share; }
/** * 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; } }
/** * @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; }
/** * @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; } }