urlGenerator = $urlGenerator; $this->rootFolder = $rootFolder; $this->shareManager = $shareManager; $this->userId = $UserId; $this->bookmarkService = $bookmarkService; $this->preferenceService = $preferenceService; } /** * @PublicPage * @NoCSRFRequired */ public function showReader(): TemplateResponse { $templates = [ 'application/epub+zip' => 'epubreader', 'application/x-cbr' => 'cbreader', 'application/pdf' => 'pdfreader' ]; /** * @var array{ * fileId: int, * fileName: string, * fileType: string * } $fileInfo */ $fileInfo = $this->getFileInfo((string) $this->request->getParam('file')); $fileId = $fileInfo['fileId']; $type = (string) $this->request->getParam('type'); $scope = $template = $templates[$type]; $params = [ 'urlGenerator' => $this->urlGenerator, 'downloadLink' => $this->request->getParam('file'), 'scope' => $scope, 'fileId' => $fileInfo['fileId'], 'fileName' => $fileInfo['fileName'], 'fileType' => $fileInfo['fileType'], 'cursor' => $this->toJson($this->bookmarkService->getCursor($fileId)), 'defaults' => $this->toJson($this->preferenceService->getDefault($scope)), 'preferences' => $this->toJson($this->preferenceService->get($scope, $fileId)), 'metadata' => $this->toJson([]), 'annotations' => $this->toJson($this->bookmarkService->get($fileId)) ]; $policy = new ContentSecurityPolicy(); $policy->addAllowedStyleDomain('\'self\''); $policy->addAllowedStyleDomain('blob:'); $policy->addAllowedScriptDomain('\'self\''); $policy->addAllowedFrameDomain('\'self\''); $policy->addAllowedFontDomain('\'self\''); $policy->addAllowedFontDomain('data:'); $policy->addAllowedFontDomain('blob:'); $policy->addAllowedImageDomain('blob:'); $response = new TemplateResponse($this->appName, $template, $params, 'blank'); $response->setContentSecurityPolicy($policy); return $response; } /** * @brief sharing-aware file info retriever * * Work around the differences between normal and shared file access * (this should be abstracted away in OC/NC IMnsHO) * * @param string $path path-fragment from url * * @throws NotFoundException|InvalidPathException */ private function getFileInfo(string $path): array { $count = 0; $shareToken = preg_replace("/(?:\/index\.php)?\/s\/([A-Za-z0-9]{15,32})\/download.*/", "$1", $path, 1, $count); if ($count === 1) { /* shared file or directory */ $node = $this->shareManager->getShareByToken($shareToken)->getNode(); $type = $node->getType(); /* shared directory, need file path to continue, */ if ($type == FileInfo::TYPE_FOLDER && $node instanceof Folder) { $query = []; parse_str(parse_url($path, PHP_URL_QUERY), $query); if (isset($query['path']) && is_string($query['path'])) { $node = $node->get($query['path']); } elseif (isset($query['files']) && is_string($query['files'])) { $node = $node->get($query['files']); } else { throw new NotFoundException('Shared file path or name not set'); } } $filePath = $node->getPath(); $fileId = $node->getId(); } else { $filePath = $path; $fileId = $this->rootFolder->getUserFolder($this->userId) ->get(preg_replace("/.*\/remote.php\/webdav(.*)/", "$1", rawurldecode((string) $this->request->getParam('file')))) ->getId(); } $pathInfo = pathInfo($filePath); if (!is_array($pathInfo)) { throw new InvalidPathException("Can not get info for $filePath"); } return [ 'fileName' => $pathInfo['filename'], 'fileType' => strtolower($pathInfo['extension'] ?? ''), 'fileId' => $fileId ]; } private function toJson(array $value): string { return htmlspecialchars(json_encode($value), ENT_QUOTES, 'UTF-8'); } }