From c424e036a0df053c1d0063da1db9d0e28fcb99ca Mon Sep 17 00:00:00 2001 From: Martin Eiber Date: Tue, 28 Mar 2023 15:40:51 +0200 Subject: [PATCH] [Bug]: Calling absolute document URL of Sites should not be possible (#14706) * Calling absolute document URL of Sites is not possible and returns a 404 Not Found error. * Fix Type hint. * Updated caching strategy. * Change check statement. * Remove empty line. * Add Runtime Cache. * use isFrontendRequestByAdmin() instate of pimcore_editmode. * Update doc. * Update doc. * Fix typo. Co-authored-by: Divesh Pahuja --------- Co-authored-by: Divesh Pahuja --- .../09_Upgrade_Notes/README.md | 1 + lib/Routing/Dynamic/DocumentRouteHandler.php | 17 +++++- lib/Tool/Frontend.php | 52 +++++++++++++++---- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md b/doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md index 9c091e2501d..5f8b41f3672 100644 --- a/doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md +++ b/doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md @@ -271,6 +271,7 @@ pimcore: - Moved implementation of `PimcoreBundleAdminSupportInterface` from `AbstractPimcoreBundle` to bundle classes. Moved `getJsPaths`, `getCssPaths`, `getEditmodeJsPaths` and `getEditmodeCssPaths` from `AbstractPimcoreBundle` to `BundleAdminSupportTrait`. - [Cache] Responses containing a header `Cache-Control: no-cache`, `Cache-Control: private` or `Cache-Control: no-store` will no longer be cached by the full page cache. +- [Sites] Calling absolute path from a site is not possible anymore. If the absolute path is called, a 404 error will be returned instead. ## 10.6.0 diff --git a/lib/Routing/Dynamic/DocumentRouteHandler.php b/lib/Routing/Dynamic/DocumentRouteHandler.php index 3332056340c..398fed8a463 100644 --- a/lib/Routing/Dynamic/DocumentRouteHandler.php +++ b/lib/Routing/Dynamic/DocumentRouteHandler.php @@ -24,6 +24,9 @@ use Pimcore\Model\Document; use Pimcore\Model\Document\Page; use Pimcore\Routing\DocumentRoute; +use Pimcore\Tool; +use Pimcore\Tool\Frontend; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Exception\RouteNotFoundException; use Symfony\Component\Routing\RouteCollection; @@ -103,11 +106,21 @@ public function getRouteByName(string $name): ?DocumentRoute public function matchRequest(RouteCollection $collection, DynamicRequestContext $context): void { $document = Document::getByPath($context->getPath()); + $site = $this->siteResolver->getSite($context->getRequest()); + + // If the request is not from a site and the document is part of a site + // or the ID of the requested site does not match the site where the document is located. + // Then we have to throw a NotFoundHttpException + if(!$site && $document && !Tool::isFrontendRequestByAdmin()) { + $siteIdOfDocument = Frontend::getSiteIdForDocument($document); + if($siteIdOfDocument) { + throw new NotFoundHttpException("The page does not exist on this configured site."); + } + } + // check for a pretty url inside a site if (!$document && $this->siteResolver->isSiteRequest($context->getRequest())) { - $site = $this->siteResolver->getSite($context->getRequest()); - $sitePrettyDocId = $this->documentService->getDao()->getDocumentIdByPrettyUrlInSite($site, $context->getOriginalPath()); if ($sitePrettyDocId) { if ($sitePrettyDoc = Document::getById($sitePrettyDocId)) { diff --git a/lib/Tool/Frontend.php b/lib/Tool/Frontend.php index 3480e826779..a2cb97c9474 100644 --- a/lib/Tool/Frontend.php +++ b/lib/Tool/Frontend.php @@ -24,6 +24,7 @@ final class Frontend { + public static function isDocumentInSite(?Site $site, Document $document): bool { $inSite = true; @@ -51,25 +52,54 @@ public static function isDocumentInCurrentSite(Document $document): bool public static function getSiteForDocument(Document $document): ?Site { - $cacheKey = 'sites_full_list'; - if (RuntimeCache::isRegistered($cacheKey)) { - $sites = RuntimeCache::get($cacheKey); - } else { - $sites = new Site\Listing(); - $sites->setOrderKey('(SELECT LENGTH(`path`) FROM documents WHERE documents.id = sites.rootId) DESC', false); - $sites = $sites->load(); - RuntimeCache::set($cacheKey, $sites); + $siteIdOfDocument = self::getSiteIdForDocument($document); + + if(!$siteIdOfDocument) { + return null; } - foreach ($sites as $site) { - if (strpos($document->getRealFullPath(), $site->getRootPath() . '/') === 0 || $site->getRootDocument()->getId() == $document->getId()) { - return $site; + return Site::getById($siteIdOfDocument); + + } + + public static function getSiteIdForDocument(Document $document): ?int + { + $siteMapping = self::getSiteMapping(); + + foreach ($siteMapping as $sitePath => $id) { + if (str_starts_with($document->getRealFullPath(), $sitePath)) { + return $id; } } return null; } + private static function getSiteMapping() : array + { + $cacheKey = 'sites_path_mapping'; + + if(RuntimeCache::isRegistered($cacheKey)) { + return RuntimeCache::get($cacheKey); + } + + $siteMapping = Pimcore\Cache::load($cacheKey); + + if(!$siteMapping) { + $siteMapping = []; + $sites = new Site\Listing(); + $sites->setOrderKey('(SELECT LENGTH(`path`) FROM documents WHERE documents.id = sites.rootId) DESC', false); + $sites = $sites->load(); + foreach ($sites as $site) { + $siteMapping[$site->getRootPath()] = $site->getId(); + } + Pimcore\Cache::save($siteMapping, $cacheKey, ['system', 'resource'], null, 997); + } + RuntimeCache::set($cacheKey, $siteMapping); + + return $siteMapping; + } + public static function isOutputCacheEnabled(): bool|array { $cacheService = Pimcore::getContainer()->get(FullPageCacheListener::class);