getAttribute('frontend.typoscript')->getSetupTree()->getChildByName('plugin')->getChildByName('tx_seo'); $configurationArrayWithoutDots = $this->typoScriptService->convertTypoScriptArrayToPlainArray($settingsTree->toArray()); $viewConfiguration = $configurationArrayWithoutDots['view'] ?? []; $viewFactoryData = new ViewFactoryData( templateRootPaths: $viewConfiguration['templateRootPaths'] ?? [], partialRootPaths: $viewConfiguration['partialRootPaths'] ?? [], layoutRootPaths: $viewConfiguration['layoutRootPaths'] ?? [], request: $request, format: 'xml', ); $view = $this->viewFactory->create($viewFactoryData); $sitemapType = $typoScriptConfiguration['sitemapType'] ?? 'xmlSitemap'; $view->assign('type', $request->getAttribute('routing')->getPageType()); $view->assign('sitemapType', $sitemapType); $configConfiguration = $configurationArrayWithoutDots['config'] ?? []; if (!empty($sitemapName = ($request->getQueryParams()['tx_seo']['sitemap'] ?? null))) { $xslResource = $this->getXslResource($configConfiguration, $sitemapType, $sitemapName); $this->applyDynamicContentSecurityPolicy($xslResource); $view->assign('xslFile', (string)$this->resourcePublisher->generateUri($xslResource, $request)); return $this->renderSitemap($request, $view, $configConfiguration, $sitemapType, $sitemapName); } $xslResource = $this->getXslResource($configConfiguration, $sitemapType); $this->applyDynamicContentSecurityPolicy($xslResource); $view->assign('xslFile', (string)$this->resourcePublisher->generateUri($xslResource, $request)); return $this->renderIndex($request, $view, $configConfiguration, $sitemapType); } private function renderIndex(ServerRequestInterface $request, ViewInterface $view, array $configConfiguration, string $sitemapType): string { $sitemaps = []; foreach ($configConfiguration[$sitemapType]['sitemaps'] as $sitemapName => $sitemapConfig) { $sitemapProvider = $sitemapConfig['provider'] ?? null; if (is_string($sitemapName) && is_string($sitemapProvider) && class_exists($sitemapProvider) && is_subclass_of($sitemapProvider, XmlSitemapDataProviderInterface::class) ) { /** @var XmlSitemapDataProviderInterface $provider */ $provider = GeneralUtility::makeInstance($sitemapProvider, $request, $sitemapName, $sitemapConfig['config'] ?? []); $pages = $provider->getNumberOfPages(); for ($page = 0; $page < $pages; $page++) { $sitemaps[] = [ 'key' => $sitemapName, 'page' => $page, 'lastMod' => $provider->getLastModified(), ]; } } } $view->assign('sitemaps', $sitemaps); return $view->render('Index'); } private function renderSitemap(ServerRequestInterface $request, ViewInterface $view, array $configConfiguration, string $sitemapType, string $sitemapName): string { $sitemapConfig = $configConfiguration[$sitemapType]['sitemaps'][$sitemapName] ?? null; if ($sitemapConfig) { $sitemapProvider = $sitemapConfig['provider'] ?? null; if (is_string($sitemapProvider) && class_exists($sitemapProvider) && is_subclass_of($sitemapProvider, XmlSitemapDataProviderInterface::class) ) { /** @var XmlSitemapDataProviderInterface $provider */ $provider = GeneralUtility::makeInstance($sitemapProvider, $request, $sitemapName, $sitemapConfig['config'] ?? []); $items = $provider->getItems(); $view->assign('items', $items); $template = $sitemapConfig['config']['template'] ?? $sitemapConfig['template'] ?? 'Sitemap'; return $view->render($template); } throw new InvalidConfigurationException('No valid provider set for ' . $sitemapName, 1535578522); } throw new PropagateResponseException( $this->errorController->pageNotFoundAction( $request, 'No valid configuration found for sitemap ' . $sitemapName ), 1535578569 ); } /** * @throws CanNotResolvePublicResourceException * @throws CanNotResolveSystemResourceException */ private function getXslResource(array $configConfiguration, string $sitemapType, ?string $sitemapName = null): PublicResourceInterface&SystemResourceInterface { $resourceIdentifier = $configConfiguration[$sitemapType]['sitemaps'][$sitemapName ?? '']['config']['xslFile'] ?? $configConfiguration[$sitemapType]['sitemaps']['xslFile'] ?? $configConfiguration['xslFile'] ?? 'EXT:seo/Resources/Public/CSS/Sitemap.xsl'; $xslResource = $this->resourceFactory->createPublicResource($resourceIdentifier); if (!$xslResource instanceof SystemResourceInterface) { throw new \InvalidArgumentException('Can not resolve xslFile "%s" to a system resource', 1761032332); } return $xslResource; } /** * Applies `Content-Security-Policy` mutations for `unsafe-hashes` for XSLT styles. * This is done dynamically, since XSLT styles might change some day... * * The expected hash for the default XSLT styles is `sha256-d0ax6zoVJBeBpy4l3O2FJ6Y1L4SalCWw2x62uoJH15k=`. */ private function applyDynamicContentSecurityPolicy(SystemResourceInterface $xslResource): void { try { $dom = new \DOMDocument(); $dom->loadXML($xslResource->getContents()); } catch (SystemResourceDoesNotExistException) { return; } $hashes = []; foreach ($dom->getElementsByTagName('style') as $node) { if ($node->getAttribute('type') !== 'text/css') { continue; } $hashes[] = HashValue::hash($node->textContent); } if ($hashes === []) { return; } $this->policyRegistry->appendMutationCollection( new MutationCollection( new Mutation( MutationMode::Extend, Directive::StyleSrcElem, ...$hashes ) ) ); } }